hyperspeeed

Personal site of Nico Mexis

View on GitHub

Backing up my Honor 10 (COL-L29) using CVE-2024-31317

Posted: 7th March 2026
Last Update: 7th March 2026

TL;DR: How to get system user access on the Honor 10

This is what you are most likely here for. So, here you go:

  1. Install adb properly on your PC, plug in your phone and authorize it (if you have not done so yet)
  2. Download my modified exploit apk and install it on your device using adb install app-debug.apk
  3. Grant it the necessary permission using adb shell pm grant com.fh.exp31317 android.permission.WRITE_SECURE_SETTINGS
  4. Download either some netcat or toybox release containing it
  5. Push it onto the device using adb push arm64-netcat /data/local/tmp/nc and make it executable using adb shell chmod +x /data/local/tmp/nc (if you chose the toybox option instead, replace arm64-netcat with toybox-armv7l and nc with toybox in both commands)
  6. Open the necessary socket using adb shell /data/local/tmp/nc -lp 6969 (if you chose the toybox option instead, replace nc with toybox nc here)
  7. Start the “31317” app on the device, enable Alternative Payload and click Run Exploit
  8. If it worked, you should probably see something like this on the running shell:
    /system/bin/sh: can't find tty fd: No such device or address
    /system/bin/sh: warning: won't have full job control
    

    If it did not work yet, try again and again and again until it worked. Do not spam-click, though. If it still does not work after the 10th time, try to reboot the device. As soon as it is back up and you unlocked it, start again with step 6 above.

Now, you should have system user access on your Honor 10, congratulations! You can also double-check by executing whoami (which should return system).

For a good summary on what you can do with this, refer to oddbyte’s write-up.

If you want to access certain apps’ data, refer to “Gain access to any […] app’s data” in the Fire TV OS XDA thread.

Preface

Even though I have done this on a COL-L29 version Honor 10, I am rather certain that other Huawei/Honor devices may be exploitable using the same method.

So, why the hell did I even bother with this? Put simply: I “recently” got a NAS (back in October 2025, to be exact) and I wanted to back up the files from my old phones, finally. I had a long history of “smart”phones, since they usually slowed down rather fast when I was using them… Also, I got my first phone (a good ol’ Nokia) to my 10th birthday as a present from the Sparkasse (a popular bank in Germany), in case you were interested. But yeah, since then I either lost these phones or they broke so badly that I didn’t even bother recovering any data (yet). I will probably also write a few posts about backing these up in the near future, though (I have already done it - I am just too lazy to write down my thought process)!

Obstacles

Well, here we are: I want to back up my old Honor 10. Of course, I can just TWRP on it, root it, use Titanium Backup or even the TWRP-backup option. Just the usual stuff… Alas, no, I cannot. I still remember the day I got the message that a new update was available for my Honor 10 - to Android 10 (also called Android Q) back in 2020. I read the news about the update. The bootloader cannot be unlocked anymore. I didn’t mind back then, even though I was rather hesitant at first. “What could go wrong?” As it turned out, this was a rather bad decision. I even updated it a bit further until version 10.0.0.180(C432E5R1P4patch01), still EMUI 10.0.0.

Now I am stuck with an old phone that I cannot root - heck - I cannot even unlock the bootloader for god’s sake! Hence, I also cannot flash TWRP on it. But this is not where the story should end. I need to find solutions.

Looking into rooting options

Remember the old days? At least I do. There were apps like “One Click Root”, “KingRoot”, “Kingo Root”, “towelroot” etc. There was an abundance of apps that promised to just root your phone for free - with just ONE click of a button. And yes, most of these actually worked (some may have spied on your phone, though). Sadly, this era is long gone and no longer an option. Nowadays, you usually go for Magisk, where you take a boot image, patch it and flash it back in order to inject the su binary, together with many other things.

However, as already mentioned, Magisk is not an option since the bootloader is locked and I cannot unlock it anymore - even if I had an unlock code (and I don’t even have one). And, furthermore, even if I had one, it would wipe all my data. A rather bad prerequisite…

But maybe there is a way to unlock the bootloader without a full reset/wipe? I found PotatoNV, which looked rather promising since it promised to unlock the bootloader of Kirin CPU devices and my Honor 10 is based on a Kirin 970. Sadly, I rather quickly noticed in their README that the tool is 100% incompatible with the Kirin 970. Its README mentions Kirin-Tool, though, which would work if you had not upgraded to EMUI 10. Once again, defeated.

Now, this is where I began digging into more exploits. I found CVE-2022-38694, which looked rather promising. But I could not get it to work correctly for this specific device. The same is true for a whole list of other exploits - but I will skip those for just a bit of brevity here. Basically, I spent two days trying out every possible exploit I could find - just to find out that most either do not work on the hardware, EMUI 10 or because I am too stupid. What are the other options?

Jailbreaking the Fire TV Stick

Now, where does this odd section title come from? In 2024, Tom Hebb and Read Team X found a new vulnerability in Android, CVE-2024-31317. It (ab)uses the Zygote process in Android to execute arbitrary commands as any app or the system user on any Android device that is susceptible to this exploit.

Important: the system user is NOT the same as the root user. It has far less capabilities, but can still help here - you will see how and why!

The vulnerability was originally fixed on Android builds with a path level of June 2024 or later. However, apparently Amazon has overlooked it and so, their Fire TV cubes/sticks/TVs/tablets on Fire OS 7 and Fire OS 8 stayed vulnerable until October 2025 because Pro-me3us published an easy-to-follow guide on XDA on how to use it in order to “jailbreak” the respective devices. There, the system user access can be used to disable arbitrary apps/packages to block updates, set custom launchers etc.

When the news about this exploit spread in September 2025, I immediately jailbroke my Fire TV Cube (3rd Gen) and put Projectivy Launcher on it. But that’s besides my point: I began remembering this exploit and thought about whether I can use it to backup my app data.

Trying out CVE-2024-31317 on the Honor 10

Since my Honor 10 was on Android 10 and Fire TV OS 8 is also based on Android 10, I thought the odds were on my side and I decided to try it out. However, I was not prepared for the emotional rollercoaster that was about to begin.

Let’s try out the same exploit commands that are used for Fire TV devices. Rather quickly, we notice a problem:

toybox: Unknown command nc

Uh, where does this come from now? Looking at toybox’s news page, I can see changes to the nc (or netcat) subcommand even back in version 0.4.6 (2013!). So, why is it not supported? toybox nc does not work and neither does toybox netcat or even just nc or netcat. It seemed like they deliberately patched the netcat command out of the entire system.

But why? The vulnerability was not even discovered back when the 10.0.0.180 version came out. So, they must have either anticipated that it may be (ab)used in such a way or they were just extra careful to not include anything that is not useful to the “average” user in their eyes. A quick comparison of the subcommands between Fire TV OS’s and EMUI’s toybox was rather surprising though: EMUI’s toybox had a lot more subcommands/capabilities - it is JUST netcat and nc that are missing there. So, they must have known or anticipated something, most likely…

Running my own netcat

What is stopping me from just putting my own netcat binary onto the system, though? I quickly identified a fitting one here and pushed it onto the device using adb push and tried to run it:

/system/bin/sh: ./arm64-netcat: can't execute: Permission denied

Ah yeah, I forgot making the file executable, right? A quick chmod +x arm64-netcat should fix the problem… No, it doesn’t?!

As it turns out, I put the file into /sdcard - and that is mounted without executable permissions. A quick search online lead me to the directory /data/local/tmp, where this should be possible. So, I copied the file there, made it executable and it works! I now have a functioning netcat installed.

In order to test the exploit once again, I edited the commands I need to run by replacing toybox nc with /data/local/tmp/arm64-netcat. No error is thrown now, but the last nc commands exits with error code 1 and I do not have a system user shell. I tried tinkering around with all the parameters of the exploit, but none seemed to work. Was the netcat binary problematic? Is this a dead end after all? I had no idea.

Gaining app data access on my wife’s phone

It’s time for something different. I spent way too much time on this phone by now. So, I may as well back up some other phone in between. Before my wife got a new Samsung S23+, she had a Redmi Note 8 Pro, running Android 11. Since its bootloader is locked and I did not want to waste too much time, I just tried out CVE-2024-31317 once more on this device.

And it worked instantly without any modifications to the script from the XDA post for Fire TV OS?! Now, I am intrigued. Not only does this MIUI-based phone ship netcat as part of toybox, but it also does not have any additional precautions for this vulnerability in place. Perfect! Why does it work here and not on the 1-2 years older Honor 10? Let’s investigate…

The haunted system user

After some tinkering with my wife’s phone, I found out that the system user cannot access /data/local/tmp at all. Hence, my custom netcat binary is inaccessible for the system user and hence, the remote shell cannot spawn. A bit later, I found out that oddbyte actually also acknowledged this in their documentation about the system user. Another dead end.

Sadly, I cannot just install my netcat binary into /system/bin as the /system partition is mounted in read-only mode, by default. I searched for directories that both the system user and shell user can access, but did not find something that worked for my needs.

At some point here, I read oddbyte’s documentation and found this line:

This means that any binaries you want to run (like the exp.so used to throw the shell) must be included as a “library” in a installed app.

While this is 100% possible, I was just too lazy right now to compile an apk (a big mistake!) and instead thought about other ways to get the netcat or fitting toybox binary into some directory that system can access. For example, I could base64 encode it beforehand and put the string into the payload to decode it and put it into the right place. But there are apparently also limits to how much data the exploit payload can hold, according to the original blogpost.

So, this was out of the question and again, I searched for other options. I should have just packed it into an apk at this point : ^)

My half-savior: oddbyte

fuhei built an app that is able to apply the exploit by just clicking a button on the device (after granting the app the required permissions). oddbyte created a fork of that project and improved it by adding some functionalities/settings as well as a precompiled apk in the GitHub releases. I quickly noticed that this file is not very up to date and compiled it myself in order to profit from the new features:

./gradlew build
adb install app/build/outputs/apk/debug/app-debug.apk
adb shell pm grant com.fh.exp31317 android.permission.WRITE_SECURE_SETTINGS

Then, I started the app on my wife’s phone first in order to have a baseline to compare to. This version of the exploit works in a sort of “reverse way” in comparison to the Fire TV OS version. In the latter, the system user opens a socket by running netcat. In this app, the exp.so binary tries to connect to some socket that is already open. So, I needed to open this socket somehow before running the exploit:

adb shell toybox nc -lp 6969

Yes, the app uses the funny number as port. Now that the socket is in place, I clicked the “Run Exploit” button and I got some messages over at my shell:

/system/bin/sh: can't find tty fd: No such device or address
/system/bin/sh: warning: won't have full job control

I didn’t really mind those, but I knew that something apparently happened. A quick whoami revealed: system. We are in!

Ironing out the last few kinks

At this point, I believed that I may not be that far away from “jailbreaking” my Honor 10 (yes, at this point we can really call it that)… I installed the app using the exact same way and clicked the button, but still: nothing happened. What is it now, my Honor?

Let’s take a look at the output of adb logcat:

Exception executing zygote command:
java.lang.IllegalStateException: IOException on command socket
 at com.android.internal.os.ZygoteConnection.processOneCommand(ZygoteConnection.java:142)
 at com.android.internal.os.ZygoteServer.runSelectLoop(ZygoteServer.java:473)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1088)
Caused by: java.io.IOException: Invalid wire format
 at com.android.internal.os.Zygote.readArgumentList(Zygote.java:872)
 at com.android.internal.os.ZygoteConnection.processOneCommand(ZygoteConnection.java:137)
 ... 2 more
Failed to set API blacklist exemptions
java.io.IOException: Connection reset by peer
        at android.net.LocalSocketImpl.readba_native(Native Method)
        at android.net.LocalSocketImpl.access$300(LocalSocketImpl.java:37)
        at android.net.LocalSocketImpl$SocketInputStream.read(LocalSocketImpl.java:113)
        at java.io.DataInputStream.readFully(DataInputStream.java:198)
        at java.io.DataInputStream.readInt(DataInputStream.java:389)
        at android.os.ZygoteProcess.maybeSetApiBlacklistExemptions(ZygoteProcess.java:952)
        at android.os.ZygoteProcess.setApiBlacklistExemptions(ZygoteProcess.java:897)
        at com.android.server.am.ActivityManagerService$HiddenApiSettings.update(ActivityManagerService.java:2542)
        at com.android.server.am.ActivityManagerService$HiddenApiSettings.onChange(ActivityManagerService.java:2570)
        at android.database.ContentObserver.onChange(ContentObserver.java:132)
        at android.database.ContentObserver.onChange(ContentObserver.java:147)
        at android.database.ContentObserver$NotificationRunnable.run(ContentObserver.java:218)
        at android.os.Handler.handleCallback(Handler.java:888)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:213)
        at android.os.HandlerThread.run(HandlerThread.java:67)
        at com.android.server.ServiceThread.run(ServiceThread.java:44)
Failed to set API blacklist exemptions!

I have no idea what this means. So, let’s take a look at the source code! I just picked out some Android 10 branch and looked at Zygote.java and ZygoteConnection.java. The line numbers do not match, but I don’t mind - I could quickly identify the line that indicated the problem: apparently there is something wrong with the argument count in the sent payload (in the case of fuhei’s/oddbyte’s app: 11). I do not see a problem with that number, though. So, it must be something different again…

This is where I began tinkering around with it and I found out that there are many different errors that can occur here - other popular examples I have encountered:

The source code basically tries to see whether the --runtime-flags parameter from the payload command is odd. If it isn’t, this error is thrown. Even though adb logcat shows me that this parameter is always odd (2049 by default), I thought I should investigate this, since I did not understand where this magic number comes from, anyway.

Comparing again with the Fire TV OS exploit from XDA, I noticed that there are a few differences between the two payloads. So, why not try to just copy that one into the app instead? This is possible with the Advanced Mode checkbox.

I rebooted the phone, enabled advanced mode, copy-pasted a slightly edited version of the string from XDA into the text area, started a shell using

adb shell /data/local/tmp/nc -lp 6969

clicked the button and nothing happened. I tried again. Suddenly:

/system/bin/sh: can't find tty fd: No such device or address
/system/bin/sh: warning: won't have full job control

I couldn’t believe my eyes! Let’s try out… Something..:

:/ $ whoami
system

I did it. Or rather: all the other people that were involved into CVE-2024-31317 did it and I just found the correct combination of tools/configurations that worked for my specific device.

And yes, I indeed have access to the app data I wanted to backup:

:/ $ ls /data/data
[...]
com.android.shell
com.android.simappdialog
com.android.soundrecorder
com.android.statementservice
com.android.stk
[...]

But I didn’t do anything!

Yes, I did not do anything here. Instead, I want to thank:

Without all of you I would not have made it this far. Thank you very much! And also thank you very much for reading this post on my four-days-long adventure.


Written by a human using 0% AI (you can probably tell - my English is not the best).