Objectif
Exploiter une vulnérabilité induite par une librairie pour obtenir une RCE (Remote Code Execution) sur une application Android.
Outils
- Jadx – https://github.com/skylot/jadx
- ADB – https://developer.android.com/tools/adb?hl=fr
- Android Lib Detector – https://github.com/rsenet/android_lib_detector
- MobSF – https://github.com/MobSF/Mobile-Security-Framework-MobSF
Sources
- https://snyk.io/fr/blog/unsafe-deserialization-snakeyaml-java-cve-2022-1471/
- https://security.snyk.io/vuln/SNYK-JAVA-ORGYAML-3152153
Installation
Pour commencer, nous allons installer l’application sur un périphérique virtuel (bien que cela fonctionne également avec les périphériques physiques), le tout grâce à ADB :
$ adb install com.mobilehackinglab.configeditor.apk
Performing Streamed Install
Success
L’application est installée avec succès et se lance parfaitement :

A première vue, il s’agit d’une application permettant de charger / sauvegarder des fichiers. Commençons l’analyse !
Les librairies
L’objectif de l’exercice étant clair — identifier une vulnérabilité dans une librairie — concentrons-nous directement sur cet aspect.
Il est important de garder en tête que deux types de librairies existent sous Android :
- Les librairies Java/Kotlin. Écrites en Java ou Kotlin et compilées en bytecode DEX, elles sont directement intégrées dans les fichiers classes.dex de l’APK.
- Les librairies natives (JNI/NDK). Écrites en C ou C++ et compilées pour chaque architecture sous forme de fichiers .so placés dans le dossier lib/ de l’APK.
Pour lister ces deux types de librairies, nous allons utiliser Android Lib Detector :

Aucune librairie native n’a été identifiée. Néanmoins, la librairie SnakeYAML peut sembler intéressante à analyser. En effet, SnakeYAML est une libraire permettant de lire et d’écrire des fichiers YAML.
En poussant la phase de reconnaissance un peu plus loin, il est possible via une simple recherche Google (« SnakeYAML vulnerability ») d’identifier une vulnérabilité (CVE-2022-1471) permettant d’exécuter du code arbitraire :

SnakeYAML et désérialisation
La librairie SnakeYAML est une librairie Java couramment utilisée pour lire et écrire des fichiers YAML. Elle peut également être embarquée dans des applications Android.
Elle permet notamment de convertir dynamiquement des structures YAML en objets Java, via un processus appelé désérialisation, qui consiste à reconstruire un objet à partir de données structurées (YAML, JSON, XML, etc.). Dans notre cas, un fichier YAML est converti en objet Java via la méthode Yaml.load().
Désérialiser du contenu non maîtrisé peut présenter un risque de sécurité. En effet, il peut être possible d’instancier n’importe quelle classe Java accessible dans le code — y compris des classes contenant des effets de bord (un gadget).
Au sein de notre APK, le problème vient du fait que, lorsque l’on utilise Yaml.load(), SnakeYAML instancie n’importe quelle classe Java si elle est accessible depuis le classpath, sans restriction :

Rappel technique : un gadget est une classe Java déjà présente dans l’application, dont le constructeur ou une méthode spéciale peut provoquer un effet de bord involontaire : exécution de commande, suppression de fichier, etc. Ces classes ne sont pas des vulnérabilités en elles-mêmes, mais deviennent dangereuses si un attaquant peut les instancier à distance via une désérialisation non sécurisée.
Exploitation de la vulnérabilité
Pour que l’exploitation de la désérialisation soit effective, il est nécessaire d’identifier un gadget pouvant avoir un effet de bord qu’un attaquant pourrait vouloir exploiter.
Pour cela, il est possible d’identifier des fonctions potentiellement dangereuses via des recherches manuelles ou via MobSF :

MobSF nous aide à identifier une potentielle exécution de commande au sein du fichier com/mobilehackinglab/configeditor/LegacyCommandUtil.java. Après analyse, la fonction LegacyCommandUtil permet d’exécuter du code arbitraire sans aucune restriction :

Maintenant que nous avons identifié la présence de la bibliothèque vulnérable (SnakeYAML), ainsi qu’un gadget exploitable (LegacyCommandUtil), il est temps de construire un scénario d’exploitation concret.
En explorant le code désassemblé avec Jadx, il est possible d’identifier deux méthodes principales dans MainActivity : loadYaml() et saveYaml(). C’est la première qui nous intéresse particulièrement, car elle contient l’appel vulnérable à SnakeYAML :
Yaml yaml = new Yaml();
Object loadedObject = yaml.load(inputStream);
Aucun SafeConstructor n’est utilisé, ce qui signifie que SnakeYAML désérialisera n’importe quel type déclaré dans le fichier YAML.
Il est alors possible de forger un fichier exploit.yml contenant les commandes que l’on veut exécuter par le biais du gadget LegacyCommandUtil de cette manière. Ces commandes permettront de créer le répertoire orhus (mkdir) ainsi que le fichier rce.txt (touch) :

En chargeant le fichier (via le bouton Load,l’application fera appel à la fonction loadYaml(), elle-même intégrant la fonction yaml.load() vulnérable permettant alors d’exécuter du code arbitraire directement sur le périphérique :

Enfin, il est important de noter que l’application déclare plusieurs permissions sensibles dans au sein du fichier AndroidManifeste.xml, notamment READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE et MANAGE_EXTERNAL_STORAGE. Cette dernière, introduite à partir d’Android 11, permet un accès complet au stockage partagé, y compris les répertoires d’autres applications.
Dans le contexte d’une exécution de code arbitraire, ces permissions élargissent considérablement la surface d’attaque : un fichier YAML malveillant pourrait non seulement exécuter des commandes, mais aussi lire et/ou modifier l’ensemble des fichiers présents sur la carte mémoire, exfiltrer des documents, ou injecter des fichiers dans d’autres applications.