Continúo incluyendo las soluciones a retos de la categoría 'Binary Exploitation' de la competición Sunshine CTF 2020.
En esta entrada la solución al desafío que lleva por título "speedrun04", y que, en mi opinión, presenta un nivel de dificultad medio (★★★☆☆).
- Enunciado:
- Solución: Se proporciona un archivo ejecutable (chall_04) y lo primero que hago es ejecutarlo; incluyo una cadena larga ('AAA…A') y veo que el binario es vulnerable a un desbordamiento de ‘buffer’ (en inglés, ‘buffer overflow’):
Después, compruebo los mecanismos de seguridad del binario utilizando ‘checksec’:
Se trata de un binario de 64 bits, y como se ve en la figura anterior NX está habilitado, por lo que no podré inyectar ‘shellcode’ en la pila (en inglés, ‘stack’) para ejecutarlo, y PIE está deshabilitado, por lo que es fácil para un atacante el uso de sus funciones y de ‘gadgets’ del propio binario (en español dispositivos, y que, en este caso, son pequeños fragmentos de código ya presentes en el binario).
Decompilo el binario con ’Ghidra’:
Veo que en main() se utiliza fgets() en lugar de gets() lo que, en principio, evitaría un desbordamiento de ‘buffer’.
Sin embargo, también veo que se realiza una llamada a la función vuln():
Esta función
también utiliza fgets() en lugar de gets(),
pero al establecerse en 100 el número de caracteres a leer para un ‘buffer’ de 56 caracteres es susceptible a un ataque de desbordamiento de ‘buffer’.
Además,
al final de esta función se realiza una llamada a una función ubicada en la dirección que contiene la variable local_10.
Tal y como he dicho, el ‘buffer’ tiene un tamaño de 56 bytes y, conforme a los nombres de las variables local_48 y local_10 en ‘Ghidra’, la dirección de retorno de la función vuln() se encontraría desplazada 0x48 (72) bytes desde la dirección de inicio del ‘buffer’ y 0x10 (16) bytes desde la dirección de inicio de la variable local_10.
Asimismo, veo que hay una función win() a la que no se llama nunca:
En esta función se hace una llamada a system() con argumento “/bin/sh”, lo que me permitiría obtener una ‘shell’ en el servidor.
Por tanto, mi plan de ataque consiste en sobrescribir el contenido de la variable local_10 con la de inicio de la función win(), con lo que obtendré una ‘shell’, podré buscar y ver la flag, y, en consecuencia, podré resolver este reto.
Para implementar el ataque creo un pequeño ‘exploit’ mediante un ‘script’ en python para que envíe 56 bytes (0x38) de relleno, tamaño del buffer (56) o, lo que es lo mismo, 0x48 - 0x10 (72 - 16), y luego la dirección de inicio de la función win() (aunque podría localizarla, por ejemplo, desensamblando el binario utilizando ‘gdb’, voy a dejar que se haga automáticamente por mí), con lo que sobrescribiré el contenido de la variable local_10 con la dirección anterior, se bifurcará a la función win() y se abrirá una ‘shell’:
#!/usr/bin/env python3
from pwn import *
binary = context.binary = ELF('./chall_04')
p = remote('chal.2020.sunshinectf.org', 30004)
p.sendlineafter('Like some kind of madness, was taking control.\n','')
payload = b'A' * 56
payload += p64(binary.sym.win)
p.sendline(payload)
p.interactive()
Lo ejecuto:
A partir de que se abra la
‘shell’,
lo único que queda por hacer es buscar la flag en el servidor. Veo que
hay un fichero llamado flag.txt que contiene la solución a este reto: sun{critical-acclaim-96cfde3d068e77bf}
Comentarios
Publicar un comentario