Le crackme étudié dans cet article provient
d’ici.
Ce second crackme est un peu moins simple que le précédent, mais il
est tout de même trivial. En revanche, je me suis compliqué la vie : la
solution était en fait bien plus simple que ce que l’on peut penser. Mais au
moins, ça me permet de présenter l’usage de GDB ^^
Comme la dernière fois, on va commencer par lancer strings sur
notre binaire. Cependant, cette fois le nombre de chaîne de caractères est
beaucoup plus important (1506 chaînes). Ayant la flemme de regarder cela en
détail (pourtant j’aurai dû, comme vous le verrez par la suite), je décide de
passer à autre chose.
Déjà, on peut remarquer (via la
commande file
ou ldd) que l’exécutable est
compilé en mode statique (ce qui explique le grand nombre de chaîne de
caractères), ça signifie que l’on peut oublier d’office les bidouilles à base
de ltrace et autres LD_PRELOAD (ne vous inquiétez
pas, on aura l’occasion de s’amuser avec ça dans d’autres défis).
Partant de ces premières observations, je décide de partir sur
GDB. Mais
avant cela, voyons une exécution normale :
Ok, il faut donc fournir un nom d’utilisateur avant de pouvoir fournir le mot
de passe.
Maintenant, passons à GDB. Première chose à faire : placer un point d’arrêt
sur la fonction main, puis regarder le code assembleur.
Information intéressante : il y a deux appels à strcmp. Ça
pourrait bien correspondre aux vérifications du nom d’utilisateur et du mot de
passe. On va donc placer un point d’arrêt sur strcmp afin de
pouvoir examiner son code.
On prend soin d’utiliser une chaîne très facilement reconnaissable en tant que
nom d’utilisateur, ça peut être utile par la suite.
En analysant le code on voit que la comparaison (instruction cmp
à l’adresse 0x0805030f) se fait sur le contenu des registres cl
et al. Ces registres correspondent en fait aux registres 32-bit
ecx et eax traités comme des registres 8-bit. Or, on
voit que les valeurs de ces registres sont chargées à partir des adresses
contenues dans esi (pour eax) et ebx
(pour ecx) via des instructions movzbl. Il suffit
donc de mettre un point d’arrêt après le chargement des adresses dans
esi et ebx afin de pouvoir afficher les chaînes de
caractères :
On reconnaît notre chaîne AAAAAAAA dans esi, c’est
donc ebx qui contient le nom d’utilisateur. On découvre alors que
le nom d’utilisateur est john.
Comme nous avons donné un mauvais mot de passe, le programme va se terminer
avant que nous puissions découvrir le mot de passe. Pour éviter cela, nous
allons modifier la valeur de retour de strcmp. On commence par
ajouter un point d’arrêt juste après le premier appel de strcmp
dans main, puis on placera 0 (valeur de retour
de strcmp lorsque les deux chaînes sont identiques) dans le
registre eax (registre utilisé pour stocker la valeur de retour,
ce comportement est défini par la
convention d’appel
utilisée) avant de continuer l’exécution.
Comme prévu, il nous demande le mot de passe et l’on se retrouve à nouveau
dans strcmp. En appliquant le même principe que précédemment on
obtient le mot de passe.
Étant maintenant en possession des identifiants, on peut récupérer le code
secret :
Gagné !
Le mot de passe était donc 987654321.
Le mot de la fin
Pour information, tout cela était inutile. En effet, la sortie
de strings nous donnait déjà toutes les informations nécessaires
(pour peu que l’on prenne le temps de la regarder de plus près) :
On voit donc que le nom d’utilisateur et le mot de passe était en clair dans
le binaire. Pis encore : le code à obtenir (987654321) est lui aussi en clair
dans le binaire. On n’avait même pas besoin de connaître le nom d’utilisateur
et le mot de passe pour y accéder.