PIN
2 minutos de lectura
Se nos proporciona un binario llamado rev1
:
$ file rev1
rev1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=c5f9af621b132c2028d8e689cbb5b707f3f3cd28, not stripped
Si lo ejecutamos, el programa espera un PIN:
$ ./rev1
Masukan PIN = 1234
PIN salah !
Vamos a depurarlo con GDB y a mostrar el código ensamblador del main
:
$ gdb -q rev1
Reading symbols from rev1...
(No debugging symbols found in rev1)
gef➤ disassemble main
Dump of assembler code for function main:
0x00000000004005d6 <+0>: push rbp
0x00000000004005d7 <+1>: mov rbp,rsp
0x00000000004005da <+4>: sub rsp,0x10
0x00000000004005de <+8>: lea rdi,[rip+0xdf] # 0x4006c4
0x00000000004005e5 <+15>: mov eax,0x0
0x00000000004005ea <+20>: call 0x4004a0 <printf@plt>
0x00000000004005ef <+25>: lea rax,[rbp-0x4]
0x00000000004005f3 <+29>: mov rsi,rax
0x00000000004005f6 <+32>: lea rdi,[rip+0xd6] # 0x4006d3
0x00000000004005fd <+39>: mov eax,0x0
0x0000000000400602 <+44>: call 0x4004b0 <__isoc99_scanf@plt>
0x0000000000400607 <+49>: mov eax,DWORD PTR [rbp-0x4]
0x000000000040060a <+52>: mov edi,eax
0x000000000040060c <+54>: call 0x4005b6 <cek>
0x0000000000400611 <+59>: test eax,eax
0x0000000000400613 <+61>: je 0x400623 <main+77>
0x0000000000400615 <+63>: lea rdi,[rip+0xba] # 0x4006d6
0x000000000040061c <+70>: call 0x400490 <puts@plt>
0x0000000000400621 <+75>: jmp 0x40062f <main+89>
0x0000000000400623 <+77>: lea rdi,[rip+0xba] # 0x4006e4
0x000000000040062a <+84>: call 0x400490 <puts@plt>
0x000000000040062f <+89>: mov eax,0x0
0x0000000000400634 <+94>: leave
0x0000000000400635 <+95>: ret
End of assembler dump.
Aquí vemos que nuestros datos de entrada se pasan a cek
, por lo que vamos a mostrar esta función:
gef➤ disassemble cek
Dump of assembler code for function cek:
0x00000000004005b6 <+0>: push rbp
0x00000000004005b7 <+1>: mov rbp,rsp
0x00000000004005ba <+4>: mov DWORD PTR [rbp-0x4],edi
0x00000000004005bd <+7>: mov eax,DWORD PTR [rip+0x200a7d] # 0x601040 <valid>
0x00000000004005c3 <+13>: cmp DWORD PTR [rbp-0x4],eax
0x00000000004005c6 <+16>: jne 0x4005cf <cek+25>
0x00000000004005c8 <+18>: mov eax,0x1
0x00000000004005cd <+23>: jmp 0x4005d4 <cek+30>
0x00000000004005cf <+25>: mov eax,0x0
0x00000000004005d4 <+30>: pop rbp
0x00000000004005d5 <+31>: ret
End of assembler dump.
Podemos poner un breakpoint en la instrucción de comparación para que podemos ver qué PIN está esperando:
gef➤ break *cek+13
Breakpoint 1 at 0x4005c3
Ahora ejecutamos el programa con cualquier PIN:
gef➤ run
Starting program: ./rev1
Masukan PIN = 1234
Breakpoint 1, 0x00000000004005c3 in cek ()
Y llegamos al breakpoint. El PIN esperado se guarda en $eax
(también está en una variable global llamada valid
):
gef➤ p/x $eax
$1 = 0x51615
gef➤ p/d $eax
$2 = 333333
gef➤ p/d (int) valid
$3 = 333333
gef➤ quit
Ahora tenemos el PIN correcto (333333
):
$ ./rev1
Masukan PIN = 333333
PIN benar !
Por lo que la flag es: CTFlearn{333333}
.