FCSC 2020 - Intro - Tarte Tatin
Votre mission : trouver le mot de passe qui affiche le flag.
SHA256(TarteTatin
) = 16697d877a69f2d06f286e32a0c1e8fc01eff25c366ef200eee47cc5ab81f96e
Résolution
Tout d’abord testons un peu notre binaire pour comprendre ce qu’il fait.
bash$ ./TarteTatin
TestString
Il n’y a pas de sortie. Procédons maintenant au désassemblage.
Désassemblage
Commençons par regarder la fonction main :
gdb-peda$ file TarteTatin
gdb-peda$ disas main
Dump of assembler code for function main:
0x00005555555547a4 <+0>: push rbp
0x00005555555547a5 <+1>: mov rbp,rsp
0x00005555555547a8 <+4>: sub rsp,0x30
0x00005555555547ac <+8>: mov rax,QWORD PTR fs:0x28
0x00005555555547b5 <+17>: mov QWORD PTR [rbp-0x8],rax
0x00005555555547b9 <+21>: xor eax,eax
0x00005555555547bb <+23>: mov rdx,QWORD PTR [rip+0x2008ce] # 0x555555755090 <stdin@@GLIBC_2.2.5>
0x00005555555547c2 <+30>: lea rax,[rbp-0x30]
0x00005555555547c6 <+34>: mov esi,0x20
0x00005555555547cb <+39>: mov rdi,rax
0x00005555555547ce <+42>: call 0x555555554650 <fgets@plt>
0x00005555555547d3 <+47>: lea rax,[rbp-0x30]
0x00005555555547d7 <+51>: mov rdi,rax
0x00005555555547da <+54>: call 0x55555555477a <transform>
0x00005555555547df <+59>: lea rax,[rbp-0x30]
0x00005555555547e3 <+63>: mov edx,0x10
0x00005555555547e8 <+68>: lea rsi,[rip+0x200891] # 0x555555755080 <pass_enc>
0x00005555555547ef <+75>: mov rdi,rax
0x00005555555547f2 <+78>: call 0x555555554640 <memcmp@plt>
0x00005555555547f7 <+83>: test eax,eax
0x00005555555547f9 <+85>: jne 0x55555555481a <main+118>
0x00005555555547fb <+87>: lea rdi,[rip+0x20081e] # 0x555555755020 <flag_enc>
0x0000555555554802 <+94>: call 0x55555555477a <transform>
0x0000555555554807 <+99>: lea rdi,[rip+0x200812] # 0x555555755020 <flag_enc>
0x000055555555480e <+106>: call 0x555555554620 <puts@plt>
0x0000555555554813 <+111>: mov eax,0x1
0x0000555555554818 <+116>: jmp 0x55555555481f <main+123>
0x000055555555481a <+118>: mov eax,0x0
0x000055555555481f <+123>: mov rcx,QWORD PTR [rbp-0x8]
0x0000555555554823 <+127>: xor rcx,QWORD PTR fs:0x28
0x000055555555482c <+136>: je 0x555555554833 <main+143>
0x000055555555482e <+138>: call 0x555555554630 <__stack_chk_fail@plt>
0x0000555555554833 <+143>: leave
0x0000555555554834 <+144>: ret
End of assembler dump.
gdb-peda$
Nous allons placer un breakpoint juste après la sortie de la fonction transform
pour comprendre ce qu’elle fait :
0x00005555555547d7 <+51>: mov rdi,rax
0x00005555555547da <+54>: call 0x55555555477a <transform>
=> 0x00005555555547df <+59>: lea rax,[rbp-0x30]
0x00005555555547e3 <+63>: mov edx,0x10
Plaçons donc le breakpoint à l’adresse 0x00005555555547df
:
gdb-peda$ breakpoint * 0x00005555555547df
Nous allons également placer un breakpoint juste avant l’appel à la fonction <memcmp@plt>
pour regarder le contenu des zones mémoire qui vont être comparées. La fonction memcmp
compare les données pointées par les adresses mémoire stockées dans les registres RSI
et RDI
. Nous voyons que les données à comparer sont chargées juste avant l’appel à memcmp
dans les registres RSI
et RDI
.
0x5555555547e8 <main+68>: lea rsi,[rip+0x200891] # 0x555555755080 <pass_enc>
=> 0x5555555547ef <main+75>: mov rdi,rax
0x5555555547f2 <main+78>: call 0x555555554640 <memcmp@plt>
Plaçons donc le breakpoint à l’adresse 0x00005555555547ef
:
gdb-peda$ breakpoint * 0x00005555555547ef
Maintenant nous allons lancer le programme dans GDB. Tapez la commande run
, puis le programme se lance. Nous n’avons pas encore atteint de breakpoint donc le programme TarteTatin
attend l’entrée utilisateur. Entrez un string que vous reconnaitrez en mémoire, par exemple ViveLesCrepes
puis tapez entrée.
Nous avons atteint ici le premier breakpoint à l’adresse 0x00005555555547df
situé après le retour de la fonction transform
. La sortie de la fonction transform
, située dans le regsitre RSI
, est WjwfMftDsfqft
. Nous pouvons aisément remarquer que chaque lettre de notre entrée transformée WjwfMftDsfqft
est la lettre située juste après la lettre originale de notre entrée. En effet :
V => W
i => j
v => w
e => f
L => M
e => f
s => t
C => D
r => s
e => f
p => q
e => f
s => t
Continuons maintenant l’exécution du programme. Pour cela tapez continue
pour continuer l’exécution jusqu’au prochain breakpoint.
Nous avons atteint ici le second breakpoint à l’adresse 0x00005555555547ef
situé juste avant l’appel à la fonction <memcmp@plt>
. Affichons donc le contenu des registres RSI
et RDI
:
gdb-peda$ x/s $rdi
0x7fffffffde80: "WjwfMftDsfqft\v"
gdb-peda$ x/s $rsi
0x555555755080 <pass_enc>: "NzTfdvs4Q4ttx1se"
Le registre rdi
contient notre entrée utilisateur, et le registre rsi
, contient le mot de passe encodé pass_enc
dont la valeur est NzTfdvs4Q4ttx1se
.
Nous écrivons un petit script python pour enlever 1
à chaque code caractère du pass_enc
:
pass_enc = "NzTfdvs4Q4ttx1se"
pass_dec = ""
for c in pass_enc:
pass_dec += chr(ord(c) - 1)
print('[+] pass_dec :',pass_dec)
Pour les habitués du python, la syntaxe des “list comprehensions” est plus rapide je trouve :
pass_enc = "NzTfdvs4Q4ttx1se"
pass_dec = ''.join([chr(ord(c) - 1) for c in pass_enc])
print('[+] pass_dec :',pass_dec)
Nous obtenons le mot de passe MySecur3P3ssw0rd
, essayons le en entrée du binaire :
bash$ ./TarteTatin
MySecur3P3ssw0rd
Well done! The flag is: FCSC{83f41431c111062d003dd0213cf824d66f770a0be1305e2813f15dd76503a91d}
Le flag est FCSC{83f41431c111062d003dd0213cf824d66f770a0be1305e2813f15dd76503a91d}
BONUS - La technique forensics-like
(Pour ceux qui n’aiment pas le désassemblage)
Nous allons extraire les strings présents dans le binaire :
bash$ strings -a TarteTatin
...
EBRBz72e30320b000/51c//2cc/102be713c55e66/`/ad02/4d1702e04cc654/2`80c|
NzTfdvs4Q4ttx1seGCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
...
transform
main
flag_enc
pass_enc
...
Un des strings attire l’oeil pour deux raisons, il est long, et il commence par EBRB
:
EBRBz72e30320b000/51c//2cc/102be713c55e66/`/ad02/4d1702e04cc654/2`80c|
Les lettres EBRB
sont les lettres juste avant les lettres de FCSC
. Essayons donc d’enlever 1
aux codes caractères de ce string :
$ python3
Python 3.6.9 [GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> flag_enc = "EBRBz72e30320b000/51c//2cc/102be713c55e66/`/ad02/4d1702e04cc654/2`80c|"
>>> flag_dec = ''.join([chr(ord(c)+1) for c in flag_enc])
>>> print(flag_dec)
FCSC{83f41431c111062d003dd0213cf824d66f770a0be1305e2813f15dd76503a91d}
>>>
Et voilà nous avons le flag sans désassembler de binaire !
Le flag est FCSC{83f41431c111062d003dd0213cf824d66f770a0be1305e2813f15dd76503a91d}