Auteur : Ayoub Laafar
Difficulté : ⭐⭐⭐ Hard
Catégorie : Android Reverse Engineering
Flag :PWNSEC{W3'r3_N0t_T00l5_0f_The_g0v3rnm3n7_0R_4ny0n3_3ls3}
Analyser et bypasser les protections d'une application Android (anti-root, anti-Frida, anti-ptrace), puis exploiter une vulnérabilité CVE-2022-1471 (SnakeYAML) pour déclencher l'exécution d'une fonction native JNI qui génère le flag.
- Émulateur : Pixel 3 API 28 x86 (Google APIs)
- Outils :
apktool 3.0.1,Jadx-GUI,Ghidra,ADB,VS Code,PowerShell
On commence par décompiler l'APK avec Jadx-GUI pour comprendre le flux de l'application.
Points clés identifiés dans MainActivity :
- La méthode
isDeviceRooted()effectue plusieurs vérifications anti-root - Si l'Intent contient l'extra
SNAKE=BigBoss, l'app lit le fichier/sdcard/Snake/Skull_Face.yml - Ce fichier est parsé avec SnakeYAML, ce qui déclenche la désérialisation de la classe
BigBoss - La classe
BigBosscontient une méthode native JNIstringFromJNI()qui génère le flag
java -jar apktool_3.0.1.jar d snake.apk -o snake_smaliOn remplace le corps de la méthode isDeviceRooted() pour qu'elle retourne toujours false :
.method public static isDeviceRooted(Landroid/content/Context;)Z
.registers 1
const/4 v0, 0x0
return v0
.end methodOn change le chemin de lecture du fichier YAML de getFilesDir() vers getExternalStorageDirectory() avec le dossier Snake :
invoke-static {}, Landroid/os/Environment;->getExternalStorageDirectory()Ljava/io/File;
...
const-string v2, "Snake"On active l'extraction des librairies natives :
android:extractNativeLibs="true"La librairie native libsnake.so contient une détection avancée via ptrace(PTRACE_TRACEME). Si ptrace retourne -1, l'app appelle exit(1).
lVar1 = ptrace(PTRACE_TRACEME, 0, 0, 0);
if (lVar1 == -1) {
exit(1); // ← à bypasser
}On identifie l'instruction JZ à l'adresse 0x7344e dans Ghidra et on la change en JNZ pour inverser la logique :
JZ=0F 84→JNZ=0F 85
On exporte la librairie patchée depuis Ghidra au format Original File :
On identifie les offsets exacts dans le fichier et on applique le patch :
$offsets = @(0x872B5, 0x87875, 0x88FA5, 0x89565)
foreach ($offset in $offsets) {
$bytes[$offset+9] = 0x85 # JZ (84) → JNZ (85)
}# Recompile
java -jar apktool_3.0.1.jar b snake_smali -o snake_patched.apk
# Zipalign
zipalign -f -v 4 snake_patched.apk snake_final.apk
# Création du keystore
keytool -genkey -v -keystore my-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias mykey# Signature avec apksigner
apksigner sign --ks my-key.jks --out snake_signed.apk snake_final.apkOn crée le fichier Skull_Face.yml qui exploite la désérialisation non sécurisée de SnakeYAML 1.33 :
!!com.pwnsec.snake.BigBoss ["Snaaaaaaaaaaaaaake"]Explication du payload :
!!com.pwnsec.snake.BigBoss: instanciation directe de la classe Java via un global tag YAML["Snaaaaaaaaaaaaaake"]: argument passé au constructeur- Lors de la désérialisation, SnakeYAML instancie
BigBoss, ce qui déclenche l'appel destringFromJNI()et génère le flag
# Installation
adb install snake_signed.apk
# Copie du fichier YAML
adb shell mkdir -p /sdcard/Snake
adb push Skull_Face.yml /sdcard/Snake/Skull_Face.yml
# Permission de lecture stockage
adb shell pm grant com.pwnsec.snake android.permission.READ_EXTERNAL_STORAGE
# Lancement avec l'Intent approprié
adb shell am start -n com.pwnsec.snake/.MainActivity -e SNAKE BigBossadb logcat -d | Select-String -Pattern "PWNSEC|BigBoss"PWNSEC{W3'r3_N0t_T00l5_0f_The_g0v3rnm3n7_0R_4ny0n3_3ls3}
| Protection | Méthode | Outil |
|---|---|---|
Anti-root (isDeviceRooted) |
Patch Smali → return false | VS Code |
| Anti-Frida (strings) | Remplacement des strings dans la lib | PowerShell |
Anti-ptrace (ptrace TRACEME) |
Patch JZ→JNZ dans libsnake.so | Ghidra + PowerShell |
| Chemin fichier YAML | Patch Smali chemin getExternalStorageDirectory/Snake |
VS Code |
- CVE-2022-1471 : Désérialisation arbitraire via SnakeYAML
Yaml.load()avecnew Yaml()(unsafe constructor) - Patch d'opcode x86 : Inversion d'un branchement conditionnel
JZ→JNZdans un binaire ELF - Smali patching : Modification du bytecode Dalvik pour bypasser les vérifications de sécurité
- Anti-debugging ptrace : Technique classique où
ptrace(PTRACE_TRACEME)retourne-1si un debugger est déjà attaché














