Solution de aitkmr pour Password Manager

intro reverse linux x86/x64

24 mai 2024

Lorsqu’on se connecte au serveur, on tombe sur GDB. On énumère dans un premier temps les fonctions pour se faire une idée du programme :

(gdb) info func
All defined functions:

Non-debugging symbols:
0x0000000000001000  _init
0x0000000000001030  puts@plt
0x0000000000001040  read@plt
0x0000000000001050  fflush@plt
0x0000000000001060  open@plt
0x0000000000001070  __cxa_finalize@plt
0x0000000000001080  _start
0x00000000000010b0  deregister_tm_clones
0x00000000000010e0  register_tm_clones
0x0000000000001120  __do_global_dtors_aux
0x0000000000001160  frame_dummy
0x0000000000001165  main
0x0000000000001320  __libc_csu_init
0x0000000000001380  __libc_csu_fini
0x0000000000001384  _fini

Je commence dans un premier temps par analyser la fonction main. Pour cela je la désassemble à l’aide de la commande disass main :

(gdb) disass main
Dump of assembler code for function main:
   0x0000000000001165 <+0>:	push   rbp
   0x0000000000001166 <+1>:	mov    rbp,rsp
   0x0000000000001169 <+4>:	sub    rsp,0x4b0
   0x0000000000001170 <+11>:	movabs rax,0x491e1e4f4f194b1f
   0x000000000000117a <+21>:	movabs rdx,0x4e481c1d4e191c1d
   0x0000000000001184 <+31>:	mov    QWORD PTR [rbp-0x460],rax
   0x000000000000118b <+38>:	mov    QWORD PTR [rbp-0x458],rdx
   0x0000000000001192 <+45>:	movabs rax,0x4e12484f1818181a
   0x000000000000119c <+55>:	movabs rdx,0x4b1f491f1c181348
   0x00000000000011a6 <+65>:	mov    QWORD PTR [rbp-0x450],rax
   0x00000000000011ad <+72>:	mov    QWORD PTR [rbp-0x448],rdx
   0x00000000000011b4 <+79>:	movabs rax,0x184c18131f1a1b1a
   0x00000000000011be <+89>:	movabs rdx,0x1b1b194b4b1e4e1e
   0x00000000000011c8 <+99>:	mov    QWORD PTR [rbp-0x440],rax
   0x00000000000011cf <+106>:	mov    QWORD PTR [rbp-0x438],rdx
   0x00000000000011d6 <+113>:	movabs rax,0x4c1f49181d4b1f48
   0x00000000000011e0 <+123>:	movabs rdx,0x131f4819131c4e1f
   0x00000000000011ea <+133>:	mov    QWORD PTR [rbp-0x430],rax
   0x00000000000011f1 <+140>:	mov    QWORD PTR [rbp-0x428],rdx
   0x00000000000011f8 <+147>:	mov    DWORD PTR [rbp-0x420],0x5e525e04
   0x0000000000001202 <+157>:	mov    QWORD PTR [rbp-0x4b0],0x0
   0x000000000000120d <+168>:	mov    QWORD PTR [rbp-0x4a8],0x0
   0x0000000000001218 <+179>:	mov    QWORD PTR [rbp-0x4a0],0x0
   0x0000000000001223 <+190>:	mov    QWORD PTR [rbp-0x498],0x0
   0x000000000000122e <+201>:	mov    QWORD PTR [rbp-0x490],0x0
   0x0000000000001239 <+212>:	mov    QWORD PTR [rbp-0x488],0x0
   0x0000000000001244 <+223>:	mov    QWORD PTR [rbp-0x480],0x0
   0x000000000000124f <+234>:	mov    QWORD PTR [rbp-0x478],0x0
   0x000000000000125a <+245>:	mov    DWORD PTR [rbp-0x470],0x0
   0x0000000000001264 <+255>:	mov    BYTE PTR [rbp-0x46c],0x0
   0x000000000000126b <+262>:	lea    rdi,[rip+0xd96]        # 0x2008
   0x0000000000001272 <+269>:	call   0x1030 <puts@plt>
   0x0000000000001277 <+274>:	mov    rax,QWORD PTR [rip+0x2dca]        # 0x4048 <stdout@GLIBC_2.2.5>
   0x000000000000127e <+281>:	mov    rdi,rax
   0x0000000000001281 <+284>:	call   0x1050 <fflush@plt>
   0x0000000000001286 <+289>:	mov    DWORD PTR [rbp-0x4],0x0
   0x000000000000128d <+296>:	jmp    0x12b1 <main+332>
   0x000000000000128f <+298>:	mov    eax,DWORD PTR [rbp-0x4]
   0x0000000000001292 <+301>:	cdqe   
   0x0000000000001294 <+303>:	movzx  eax,BYTE PTR [rbp+rax*1-0x460]
   0x000000000000129c <+311>:	xor    eax,0x2a
   0x000000000000129f <+314>:	mov    edx,eax
   0x00000000000012a1 <+316>:	mov    eax,DWORD PTR [rbp-0x4]
   0x00000000000012a4 <+319>:	cdqe   
   0x00000000000012a6 <+321>:	mov    BYTE PTR [rbp+rax*1-0x4b0],dl
   0x00000000000012ad <+328>:	add    DWORD PTR [rbp-0x4],0x1
   0x00000000000012b1 <+332>:	cmp    DWORD PTR [rbp-0x4],0x43
   0x00000000000012b5 <+336>:	jle    0x128f <main+298>
   0x00000000000012b7 <+338>:	lea    rax,[rbp-0x4b0]
   0x00000000000012be <+345>:	mov    esi,0x0
   0x00000000000012c3 <+350>:	mov    rdi,rax
   0x00000000000012c6 <+353>:	mov    eax,0x0
   0x00000000000012cb <+358>:	call   0x1060 <open@plt>
   0x00000000000012d0 <+363>:	mov    DWORD PTR [rbp-0x8],eax
   0x00000000000012d3 <+366>:	cmp    DWORD PTR [rbp-0x8],0x0
   0x00000000000012d7 <+370>:	jns    0x12e5 <main+384>
   0x00000000000012d9 <+372>:	lea    rdi,[rip+0xd58]        # 0x2038
   0x00000000000012e0 <+379>:	call   0x1030 <puts@plt>
   0x00000000000012e5 <+384>:	lea    rcx,[rbp-0x410]
   0x00000000000012ec <+391>:	mov    eax,DWORD PTR [rbp-0x8]
   0x00000000000012ef <+394>:	mov    edx,0x80
   0x00000000000012f4 <+399>:	mov    rsi,rcx
   0x00000000000012f7 <+402>:	mov    edi,eax
   0x00000000000012f9 <+404>:	call   0x1040 <read@plt>
   0x00000000000012fe <+409>:	mov    DWORD PTR [rbp-0xc],eax
   0x0000000000001301 <+412>:	mov    eax,DWORD PTR [rbp-0xc]
   0x0000000000001304 <+415>:	cdqe   
   0x0000000000001306 <+417>:	mov    QWORD PTR [rbp+rax*8-0x410],0x0
   0x0000000000001312 <+429>:	mov    eax,0x0
   0x0000000000001317 <+434>:	leave  
   0x0000000000001318 <+435>:	ret    
End of assembler dump.

L’énoncé nous indique que “Le gestionnaire de MDP ouvre bien le fichier de mots de passe, mais ensuite il refuse d’afficher son contenu”.

Donc, dans le code assembleur ci-dessus, je cherche les appels à des fonctions pouvant ouvrir un fichier. L’instruction 0x00000000000012cb <+358>: call 0x1060 <open@plt> est candidate.

Je souhaite m’assurer que le contenu du fichier est bien lu en cherchant un appel à la fonction read : 0x00000000000012f9 <+404>: call 0x1040 <read@plt>. Pour cela, je mets un breakpoint juste après la fonction read à l’aide de la commande b *(main+409) et je lance l’exécution à l’aide de la commande run.

L’exécution ressemble à :

(gdb) b *(main+409)
Breakpoint 1 at 0x12fe
(gdb) run
Starting program: /app/password-manager 
Welcome to my super secure password manager!

Breakpoint 1, 0x00005a2bc8d242fe in main ()

Voyons voir ce que la fonction a lu. Pour cela, je consulte le manuel de la fonction read et je constate que sa signature est ssize_t read(int fd, void *buf, size_t count);. Je souhaite consulter le contenu de buf.

Etant donné que le programme est un programme x64 s’exécutant sur linux, la convention d’appel indique que le deuxième argument est passé via RSI. Donc d’après l’instruction 0x00000000000012f4 <+399>: mov rsi,rcx l’adresse recherché est contenu dans RCX. En remontant à l’instruction, qui intialise RCX : 0x00000000000012e5 <+384>: lea rcx,[rbp-0x410], on retrouve l’adresse recherché. On vérfie aussi que RBP n’est pas altéré entre l’instruction à l’adresse 0x00000000000012e5 et 0x00000000000012fe.

J’affiche ensuite à l’aide du debugger le contenu à l’addresse $rbp-0x410:

(gdb) x/s ($rbp-0x410)
0x7fffd22bc6d0:	"FCSC{da8ae129af8512620bc6c9a711392395fba426edc6713819c1baffe004024ff2}\n"