/ reverse

cyber@hack - What's my name ?

Ce challenge, le seul de la catégorie reverse, nous propose un exécutable qui fait simplement une chose, valider un nom, ce qui permet de valider le challenge.

$ ./whatsmyname
Hmm I forgot my name, do you know it ? <o/ 

En débuggant avec gdb (avec l'extension peda) le programme, on remarque une fonction intéressante dans le main :

...
   0x0000000000400829 <+130>:	mov    BYTE PTR [rax],0x0
   0x000000000040082c <+133>:	mov    rax,QWORD PTR [rbp-0x8]
   0x0000000000400830 <+137>:	mov    rdi,rax
   0x0000000000400833 <+140>:	call   0x4006f6 <checkBasicBuffer>
   0x0000000000400838 <+145>:	test   eax,eax
   0x000000000040083a <+147>:	je     0x400846 <main+159>
   0x000000000040083c <+149>:	mov    edi,0x400a17
...

checkBasicBuffer. Cette fonction serait à priori celle qui validerait le nom passé au programme pour nous donner le flag.

En regardant le contenu désassemblé de la fonction checkBasicBuffer :

...
   0x0000000000400706 <+16>:	mov    rdi,rax
   0x0000000000400709 <+19>:	call   0x4005b0 <strlen@plt>
   0x000000000040070e <+24>:	mov    DWORD PTR [rbp-0x8],eax
...
   0x0000000000400742 <+76>:	mov    rdi,rax
   0x0000000000400745 <+79>:	call   0x4005d0 <strcmp@plt>
   0x000000000040074a <+84>:	test   eax,eax
...

On remarque l'usage de 2 fonctions, strlen ainsi que strcmp. Le programme pourrait donc vérifier la taille de chaîne passée puis valider celle-ci ?

Juste après le premier strlen, on a l'instruction suivante :

=> 0x40070e <checkBasicBuffer+24>:	mov    DWORD PTR [rbp-0x8],eax

La taille de la chaîne est donc stockée dans la pile à rbp-0x8 et sera utilisée plus tard :

   0x400711 <checkBasicBuffer+27>:	movzx  eax,BYTE PTR [rip+0x2009c2]
   0x400718 <checkBasicBuffer+34>:	movsx  eax,al
=> 0x40071b <checkBasicBuffer+37>:	cmp    eax,DWORD PTR [rbp-0x8]

Ici, l'instruction à <checkBasicBuffer+27> place dans eax la valeur 0x13 (soit 19). À <checkBasicBuffer+37>, la valeur de eax est comparée à la valeur située à rbp-0x8, soit la taille de notre chaîne précédemment calculée par strlen ! Notre chaîne doit donc faire 19 caractères.

En passant une chaîne non valide de 19 caractères, nous devrions donc pouvoir atteindre l'appel à strcmp ... En mettant un breakpoint :

=> 0x400745 <checkBasicBuffer+79>:	call   0x4005d0 <strcmp@plt>
...
Guessed arguments:
arg[0]: 0x602010 ('a' <repeats 19 times>)
arg[1]: 0x400987 ("DidntHaveTheFeeling")
arg[2]: 0x400987 ("DidntHaveTheFeeling")

Bingo ! Nous avons donc ici la comparaison effectuée par le programme. La chaîne est donc comparée à DidntHaveTheFeeling.

$ ./whatsmyname
Hmm I forgot my name, do you know it ? <o/ 
DidntHaveTheFeeling
How yeah I remember now ! My name is:
flag{MyNameIsOhMyGodWeFuukedUp}

Le flag est donc flag{MyNameIsOhMyGodWeFuukedUp}.