APT593

CPCTF: Baby BoF (Vietnam)

14/07/2020

Descripción

Ya sabes que hacer…

descargar aquí

Ingeniería inversa

El reto proporciona un ejecutable que procedemos a analizar con Cutter. Podemos ver la función main(), y una función llamada huhaha() :

Dirección Función
0x401175 main
0x401162 huhaha

La función main resulta bastante sencilla y se ve de la siguiente forma: Assembly

Interpretando el código assembler y recreando la función main en C tendríamos algo similar a esto:

int main(){
    char buf[64]; // 0x40
    puts("Como te llamas: ");
    gets(buf);
    printf("Hola %s!", buf);
    return 0;
}

Podemos ver que al ejecutarse la función gets(), no se realiza ninguna validación de tamaños del buffer destino, posibilitando un Buffer Overflow clásico en la pila.

Hacemos lo mismo con la función huhaha(): Assembly

Misma que se vería así en C:

void huhaha(){
    system("cat flag.txt");
}

El camino a seguir sería saltar a la función huhaha() para obtener el flag, haciendo uso del stack based BoF en main().

Desarrollo del exploit

Recordar que un stack-based BoF nos permite redirigir la ejecución del programa a cualquier posición de memoria de nuestra preferencia, al sobreescribir el puntero de retorno de la función vulnerable, en este caso main(). Si queremos que al terminar la función main() se nos redirija a la función huhaha(), deberemos sobreescribir el puntero de retorno con la dirección de memoria que apunta a dicha función, que se encuentra en 0x401162.

Para comenzar, enviamos una cadena larga que desborde el buffer destino, para verificar que el programa crashee como se espera: Assembly

La última línea muestra claramente un segmentation fault, producido por el programa intentando acceder a una posición de memoria no permitida. Esto se debe a que parte de nuestra cadena llena de letras “A” ha sobreescrito el puntero de retorno de la función main(), haciendo que el programa crashee al finalizarse esta. Para verificarlo, podemos abrir el programa con gdb y analizar lo que ocurre:

El crash ocurre en la posición de memoria 0x40120e, misma que corresponde al final de la función main(), debido a que el tope de la pila que contiene el puntero de retorno ha sido sobreescrito por 0x6161616161616161 que corresponde al ascii de “aaaaaaaa”. El siguiente paso está en identificar que parte de la cadena ingresada sobreescribe el puntero de retorno, para lo cual utilizaremos un patrón cíclico, que no es más que una cadena sin repeticiones de texto. Para crear un patrón utilizamos la herramienta msf-pattern_create, indicando el tamaño de cadena a generar, que deberá ser en lo posible la misma que la utilizada con anterioridad. En este caso, trabajaremos con una cadena de 80 caracteres que debiera ser más que suficiente para desbordar la variable buffer con espacio para 64 caracteres solamente:

root|r1 >> msf-pattern_create -l 80
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac

Copiamos la cadena generada y la pasamos al programa en gdb:

Como podemos ver, el puntero de retorno es ahora sobreescrito por 0x6341356341346341, que es parte del patrón cíclico enviado. Si bien pudiésemos buscarlo manualmente, utilizaremos la herramienta msf-pattern_offset para identificar en que posición del patrón se encuentra la parte de interés:

root|r1 >> msf-pattern_offset -l 80 -q 0x6341356341346341
[*] Exact match at offset 72

Esto significa que el puntero de retorno se encuentra luego del caracter 72 del input del usuario. Si reemplazamos los caracteres del 73-80 (8 caracteres por tratarse de un ejecutable de 64 bits) por la dirección de memoria de la función huhaha(), el programa saltará a dicha función y nos dará la flag como resultado. Para este fin, utilizamos un pequeño script hecho con pwntools:

from pwn import *

p = process('./pwn1')

p.recvuntil(':')
p.send(b'A'* 72 + p64(0x0000000000401162) + b'\n')
p.interactive()

Nuestro script envía una cadena que tiene 72 letras A, seguidas de la posición de memoria de la función huhahah() empaquetada como un entero de 64bits, dando por terminado el ejercicio.

root|r1 >> python3 exp1.py
[+] Starting local process './pwn1': pid 27045
[*] Switching to interactive mode
 
Hola AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb\x11!
CPCTF{baaaby_bof_tututuruturu}
[*] Got EOF while reading in interactive
$