Skip to content

Ayoublaa/lab19

Repository files navigation

🐍 CTF PwnSec — Snake (Hard) — Android Reverse Engineering Writeup

Auteur : Ayoub Laafar
Difficulté : ⭐⭐⭐ Hard
Catégorie : Android Reverse Engineering
Flag : PWNSEC{W3'r3_N0t_T00l5_0f_The_g0v3rnm3n7_0R_4ny0n3_3ls3}


🎯 Objectif du Challenge

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.


🔧 Environnement

  • Émulateur : Pixel 3 API 28 x86 (Google APIs)
  • Outils : apktool 3.0.1, Jadx-GUI, Ghidra, ADB, VS Code, PowerShell

Étape 1 : Analyse statique avec Jadx

On commence par décompiler l'APK avec Jadx-GUI pour comprendre le flux de l'application.

Jadx analyse

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 BigBoss contient une méthode native JNI stringFromJNI() qui génère le flag

MainActivity analyse


Étape 2 : Décompilation Smali avec apktool

java -jar apktool_3.0.1.jar d snake.apk -o snake_smali

Décompilation Smali


Étape 3 : Patch Smali — Bypass des détections

3.1 Bypass isDeviceRooted()

On 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 method

Patch isDeviceRooted

3.2 Correction du chemin du fichier YAML

On 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"

Patch chemin fichier

3.3 Patch AndroidManifest.xml

On active l'extraction des librairies natives :

android:extractNativeLibs="true"

Patch AndroidManifest


Étape 4 : Patch de libsnake.so avec Ghidra — Bypass anti-ptrace

La librairie native libsnake.so contient une détection avancée via ptrace(PTRACE_TRACEME). Si ptrace retourne -1, l'app appelle exit(1).

Analyse dans Ghidra

lVar1 = ptrace(PTRACE_TRACEME, 0, 0, 0);
if (lVar1 == -1) {
    exit(1);  // ← à bypasser
}

Analyse ptrace dans Ghidra

Patch de l'instruction JZ → JNZ

On identifie l'instruction JZ à l'adresse 0x7344e dans Ghidra et on la change en JNZ pour inverser la logique :

  • JZ = 0F 84JNZ = 0F 85

Patch JZ vers JNZ

Export de la librairie patchée

On exporte la librairie patchée depuis Ghidra au format Original File :

Export Ghidra

Patch PowerShell des offsets

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)
}

Patch PowerShell


Étape 5 : Recompilation et signature de l'APK

# 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

Création keystore

# Signature avec apksigner
apksigner sign --ks my-key.jks --out snake_signed.apk snake_final.apk

Signature APK

Compilation avec apktool


Étape 6 : Création du payload YAML (CVE-2022-1471)

On 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 de stringFromJNI() et génère le flag

Étape 7 : Lancement de l'application

# 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 BigBoss

Signature et installation


Étape 8 : Récupération du flag via logcat

adb logcat -d | Select-String -Pattern "PWNSEC|BigBoss"

Flag obtenu


🏁 Flag

PWNSEC{W3'r3_N0t_T00l5_0f_The_g0v3rnm3n7_0R_4ny0n3_3ls3}

📋 Résumé des protections bypassées

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

🔑 Concepts clés

  • CVE-2022-1471 : Désérialisation arbitraire via SnakeYAML Yaml.load() avec new Yaml() (unsafe constructor)
  • Patch d'opcode x86 : Inversion d'un branchement conditionnel JZJNZ dans 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 -1 si un debugger est déjà attaché

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors