Objectif
Exploiter l’application pour obtenir le flag. Le flag suit le format « MHL{…} ».
Outil
- Jadx – https://github.com/skylot/jadx
- ADB – https://developer.android.com/tools/adb?hl=fr
- CyberChef – https://gchq.github.io/CyberChef/
- Ghidra (optionnel) – https://github.com/NationalSecurityAgency/ghidra/
- Frida – https://github.com/frida
- DeployMyFridaEnv – https://github.com/rsenet/DeployMyFridaEnv
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.strings.apk
Performing Streamed Install
Success
L’application est installée avec succès et se lance parfaitement avec un simple message affiché :

Commençons l’analyse !
AndroidManifest.xml
Voici le fichier AndroidManifest.xml de l’application en question :

Il est possible d’identifier deux activity exportées, c’est-à-dire accessibles par d’autres applications du système :
- com.mobilehackinglab.challenge.MainActivity est l’activity qui sera lancée par défaut quand l’utilisateur clique sur l’icône de l’application.
- com.mobilehackinglab.challenge.Activity2 quant à elle, est une activity pouvant être déclenchée depuis un navigateur ou une application. Cette dernière peut être déclenchée par des URI de type mhl://labs, aussi appelées deep links.
Pour rappel, les deep links (Android >= 6.0) sont des URI conçues pour s’ouvrir directement dans une application mobile, guidant les utilisateurs vers un contenu ou une action spécifique sans passer par l’écran d’accueil de l’application.
Compréhension d’Activity2
Au sein d’Activity2, une partie du code nous saute aux yeux ! Il s’agit de System.loadLibrary(« flag ») pouvant être une partie intéressante à traiter. En effet, cela permet de charger la librairie native flag (fichier .so présent dans le répertoire lib/) :

Néanmoins, avant d’arriver à cette déclaration, la fonction onCreate ajoute de nombreux contrôles :
- Ligne 40
Ce contrôle vérifie que l’activité est lancée via un Intent explicite de type VIEW (isActionView) et que la valeur associée à la clé UUU0133, précédemment enregistrée dans la SharedPreferences DAD4, correspond exactement à la date du jour au format « DD/MM/YYYY« , telle que retournée par la fonction cd() (isU1Matching) :

- Ligne 42
Ce contrôle vérifie que l’URI (Uniform Resource Identifier) n’est pas null, que le schéma utilisé est égal à “mhl” (uri.getScheme()) et que l’hôte est égal à “labs” (uri.getHost()).
- Ligne 45
Ce contrôle vérifie que la variable decodedValue n’est pas null. Au sein des lignes précédentes, decodedValue correspond au dernier segment du chemin de l’URI (via l’utilisation de uri.getLastPathSegment(), le tout encodé en base64.
- Ligne 50
Ce contrôle vérifie que le dernier segment du chemin de l’URI, une fois “débase64é”, est égal à la valeur obtenue après déchiffrement AES (CBC/PKCS5Padding) d’une donnée chiffrée en dur à l’aide d’une clé statique et d’un vecteur d’initialisation (IV) connu.
En effet, au sein du code source, il est possible d’avoir les informations suivantes :
- La clé AES est codée en dur :
"your_secret_key_1234567890123456"
- L’algorithme utilisé est
AES/CBC/PKCS5Padding
- Le texte à déchiffrer est bqGrDKdQ8zo26HflRsGvVA==
- Le vecteur d’initialisation (IV) est défini via
Activity22.fixedIV

On assemble le tout !
Disposant de l’ensemble des éléments pour déchiffrer de l’AES, il est alors possible de passer ces éléments au sein de CyberChef pour obtenir la valeur secrète tant convoitée :

Il ne reste plus qu’à encoder cette valeur en base64 (via CyberChef ou autre) pour obtenir la valeur attendue par le Deep Links, à savoir bWhsX3NlY3JldF8xMzM3.
Pour passer la vérification de la ligne 40, il ne reste qu’à gérer la création de la SharedPreference. Cette dernière peut être traitée de deux manières différentes :
- Via Frida en instanciant la fonction KLOW() qui va créer la SharedPreferences
- Manuellement, en créant le fichier XML dans le répertoire shared_prefs/
Nous allons partir sur la méthode la plus rapide, la création manuelle en poussant le fichier DAD4.xml sur le système de fichier :
$ adb push DAD4.xml /data/data/com.mobilehackinglab.challenge/shared_prefs
DAD4.xml: 1 file pushed, 0 skipped. 0.2 MB/s (116 bytes in 0.001s)
Voici le contenu du fichier DAD4.xml :

On exécute le tout !
Pour permettre d’exécuter la librairie flag au sein d’Activity2, il est donc nécessaire de :
- Faire appel à Activity2 (possible car exportée)
- En utilisant le deep links mhl://labs/bWhsX3NlY3JldF8xMzM3
- En spécifiantl’intent explicite android.intent.action.VIEW
- En s’assurant de disposer d’une SharedPreferences (DAD4.xml) contenant la date du jour au sein de la clé UUU0133

Un simple message « Success », pas de flag au format MHL{…}. Ce n’est pas la fin ! Pas de problème, on va rentrer dans les détails de cette librairie (libflag.so) avec Ghidra :

On retrouve bien la fonction Java_com_mobilehackinglab_challenge_Activity2_getflag au sein de Ghidra ! Néanmoins, celle-ci semble obfusquée.
On cherche en mémoire
L’analyse statique des librairies natives est possible, mais l’obfuscation pourrait faire perdre beaucoup de temps. Voyons s’il n’est pas possible de prendre un raccourci grâce à Frida.
En effet, disposant du format du flag « MHL{…} », il est possible de chercher cette chaîne de caractère directement en mémoire grâce à Memory.scan(). Cette fonction permet d’effectuer une recherche binaire dans une zone mémoire d’un processus cible, à la recherche de motifs spécifiques (pattern matching), similaire à une attaque par texte clair connu.
Pour ce faire, nous allons rapidement déployer l’environnement Frida grâce à DeployMyFridaEnv et nous assurer que tout est fonctionnel (frida-ps -Uai) permettant également d’obtenir le PID de l’application (9215) :

Puis, réaliser une analyse mémoire de la librairie grâce au script Frida suivant (en se basant sur les templates présents ici https://github.com/rsenet/Frida-Templates) :

Il ne reste plus qu’à exécuter Frida sur le processus lancé (obtenu précédemment via frida-ps -Uai) et en utilisant le script ci-dessus afin de voir apparaître le flag tant attendu :
