by [Q]3rv[0]
Cada vez que corremos un proceso en la maquina, se crea una memoria virtual para dicho proceso, ese segmento se divide en 3 partes, el texto, los datos y por ultimo el stack, que es donde nos vamos a concentrar para realizar la explotacion de este tipo de vulnerabilidad.
¿Que es el stack?
El stack es un segmento en la memoria que se encarga de almacenar datos y a su vez recuperarlos, administra la información en modo LIFO (last in first out), quiere decir que el ultimo dato en entrar es el primero en salirUn ejemplo mas sencillo seria comparar el stack con una pila de cd's, en el que el primer cd hace de base de la pila y para llegar a el hay que retirar uno por uno los que se encuentran encima.
Entonces cada vez que se ingresa un dato al stack se utiliza una instruccion denominada PUSH y cuando se retira un dato se llama a la instruccion POP, algo similar a un array.
Los registros del procesador
El procesador cuenta con varios registros que cumplen diversas tareas en el stack, por el momento solo voy a mencionar a 3 de ellos.EIP - Registro que almacena la dirección de memoria de la proxima funcion que se va a ejecutar.
ESP - Apunta a la parte superior del stack
EBP - Aputa a la base del stack Ahora que ya se explicaron algunos conceptos basicos sobre el tema, vayamos al nudo del tutorial.
¿Que es un Buffer overflow?
#include <stdlib> #include <stdio> #include <string> int main(int argc, char *argv[]) { char buffer[10]; strcpy(buffer, argv[1]); printf(buffer); return 0; }Donde se define un buffer de 10 bytes, luego se lo pasa a la funcion strcpy que almacena en el buffer el argumento insertado por el usuario, esta misma no se encarga de controlar el tamaño limite del buffer por lo tanto si se introduce una mayor cantidad de caracteres, el espacio desbordara y comenzara a sobrescribir los registros de memoria cercanos al buffer.
Antes que nada, vamos a desactivar ASLR ASLR en criollo es un sistema de seguridad que vuelve aleatoria las direcciones de la memoria virtual.
echo 0 > /proc/sys/kernel/randomize_va_space
y compilaremos el prog con los siguientes flag de gcc.
gcc -ggdb -fno-stack-protector -mpreferred-stack-boundary=2 -o prog prog.cPara quitarle algunas protecciones al stack que le agrega gcc al compilar.
Probemos pasandole mas de 10 caracteres al programa.
gdb prog
Le pasamos los argumentos
run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
y una vez que el prog nos patee miramos en los registros a ver que encontramos?
info registers
Como se ve en la imagen, se sobrescribieron dos registros como EIP y EBP con x41, que representa el caracter A en hex.
Ahora por que crashea?, como explique anteriormente, el registro EIP contenia la direccion de la proxima funcion a ejecutar, pero al ser sobreescrito con 4 A's, EIP termina apuntando a una direccion invalida.
Sabiendo que podemos inyectar en EIP, podriamos controlar el flujo del programa y mandarlo a la direccion que se nos ocurra.
Controlando el flujo de ejecución
Le agregue la funcion owned() al programa anterior, que lo unico que hace es imprimir un texto.
#include <stdlib> #include <stdio> #include <string> void owned(){ printf("Owned :)"); } int main(int argc, char *argv[]) { char buffer[10]; strcpy(buffer, argv[1]); printf(buffer); return 0; }Pero no vamos a llamarla en el code, sino que vamos a inyectarle la direccion de memoria de owned() al EIP para asi alterar la salida del prog.
Compilamos y abrimos con gdb.
Ahora tenemos que saber el punto exacto donde empieza a sobrescribirse EIP.
Le pasamos 14 A's - nada
Le pasamos 15 A's y se puede ver como empieza a infectarse el EIP
disas owned
Ahora que tenemos la direccion con la que editaremos el EIP, solo basta restar 4 A's e incluirla.
A*14 + 0x08048408
Voy a utlizar python para realizar la inyeccion. como se ve, se utiliza el escape \x para codificar los datos.
Pero si miramos la direccion a donde apunta el EIP vemos que esta al revez, esto pasa por que los procesadores Intel utilizan el sistema little-endian por lo tanto tendremos que invertir la direccion antes de ingresarla.
Y si en vez de direccionar a una función, lograramos llegar hasta un shellcode alojado en la memoria?, eso se vera en la proximo entrada.
Saludos!