Après quelques discussions au SSTIC concernant le challenge et suite à la publication des solutions, il semble que nombreuses ont été les façons de le résoudre.

Cependant je fus étonné de ne voir qu'aucune solution présentée n'utilisait la méthode qui m'a permis d'extraire les fichiers apk de la mémoire (peut-être est-elle trop tordue).

Cette méthode passe par la récupération des structures inodes des fichiers mappés en mémoire. La grande différence de cette manière de faire est qu’elle permet l’extraction des pages de façon « propre » sans avoir à passer par la conversion mémoire virtuelle -> mémoire physique.

Ce billet a donc pour but de décrire ma démarche pour résoudre cette première partie (ayant été bloqué par la clé Elgamal, je n'ai pu valider le challenge :) ).

Il n’a donc pas vocation à être exhaustif et ne présente que la partie d’extraction des fichiers apk. Le reste ayant déjà été très bien décrit {2}.

Je vous passe la partie file et 7zip! :)

On commence donc par chercher la chaine "init" dans le fichier jusqu'à tomber sur la task_struct (on aurait pu également chercher "swapper" mais vu que la liste des processus est cyclique, cela revient au même). La structure d’une tache se présente, ainsi :

1.JPG

Nous allons ici nous intéresser à la structure mm qui va nous permettre d’arriver à la description de la mémoire du processus. On code un petit tool qui nous affiche le pointeur vers cette structure pour chaque élément de la liste :

2.jpg

Nous avons donc nos deux processus provenant de l’ANSSI (La chaîne « comm » de la structure ne pouvant contenir que 16 caractères, leurs noms sont amputés).

Afin de visualiser le chemin à parcourir pour arriver aux inodes, voici un schéma représentant les liens entre les différentes structures du noyau {1} :

14.jpg

C’est ici que la solution diverge. En effet, au lieu, de nous contenter des adresses virtuelles des segments mémoires récupérés dans les structures vm_area et de procéder à la traduction d’adresse virtuelle -> physique, nous allons descendre plus profondément pour atteindre les descripteurs de pages des fichiers mappés en mémoire.

Le principe est alors simple, nous récupérons les pointeurs sur les structures vm_area et ensuite pour chacun des segments, successivement les structures file, dentry et inode.

Il est à noter que le pointeur vers la structure file n’existe ( != NULL ) que si la zone correspond à une zone « mappée ».

Depuis la task_struct nous commençons donc par récupérer la structure mm :

6.jpg

Celle-ci nous donne, via le pointeur mmap, le début de la liste des vm_area :

15.jpg

Le pointeur file pointe vers une structure file :

8.jpg

Qui contient un pointeur sur dentry :

16.jpg

Arrivé a ce point, nous avons l’inode et le nom du fichier mappé! :)

On code alors un autre outil qui nous donne tout ça automatiquement pour un processus donné :

17.jpg

Nous découvrons ainsi que le fichier com.anssi.secret.apk est mappé dans le processus et savons que son inode (la structure) se trouve à l’adresse c5462ad8.

Explorons maintenant cette structure inode. Elle contient une autre structure adress_space (incluse) fournissant la racine d’un arbre « radix » {3}.

Ce dernier contient un ensemble de pointeurs vers les descripteurs de page.

11.jpg

Exemple d’arbre radix a deux niveaux {1}:

18.jpg

A partir des pointeurs de descripteur récupérés, nous pouvons déduire le numéro de la page si nous connaissons l’adresse de base du tableau des descripteurs (mem_map).

Je n’ai pas trouvé de méthode « propre » pour obtenir l’adresse de début de ce tableau (si quelqu’un a une autre idée, je suis preneur).

L’accès a une adresse de descripteur arbitraire puis la remontée dans le tableau avec un éditeur hexa pour trouver le début n’est, je le conçois, pas des plus élégant.

Cependant les descripteurs ayant un motif reconnaissable, l’adresse est relativement facile à trouver. (Si vous aimez les méthodes originales, je ne peux que vous conseiller la lecture de la solution par Florent Marceau {4} ;) .

L’adresse de la mem_map trouvée (0x349000) et connaissant la taille d’un descripteur (32 octets) nous pouvons alors calculer l’index de chaque page à partir d’adresse de son descripteur via la formule :

Numéro de page = (adresse descripteur – adresse mem_map) / 32

Enfin, les pages commençant à l’adresse 0 et faisant chacune 4Ko, la récupération de l’offset de la page dans le dump s’effectue via une simple multiplication :

Offset de la page = numéro de la page * 4096.

A ce niveau, un peu de code est nécessaire pour automatiser la récupération des offsets de pages associées à une structure inode. Une fois développé, nous obtenons :

13.jpg

Quelques exécutions de dd et un cat avec les bonnes valeurs et nous récupérons le fichier apk correspondant.

19.jpg

L’extraction du deuxième fichier s’effectue exactement de la même façon. Ensuite il suffit de les exécuter sur l’émulateur, etc. Mais cela a déjà été décrit dans un précédent billet par Mat {5}.

Voilà c’est fini, merci a l’ANSSI pour ce challenge.