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 "speedrun13", y que, en mi opinión, presenta un nivel de dificultad medio (★★★☆☆).
Este reto es prácticamente idéntico al que lleva por título "speedrun02".
- Enunciado:
- Solución: Se proporciona un archivo ejecutable (chall_13) y lo primero que hago es ejecutarlo; incluyo una cadena larga ('AAA…A') y el programa finaliza:
Después, compruebo los mecanismos de seguridad del binario utilizando ‘checksec’:
Se trata de un binario de 32 bits, y como se ve en la figura anterior NX está habilitado, por lo que ya sé que en el caso de que sea vulnerable a un desbordamiento de ‘buffer’ (en inglés, ‘buffer overflow’) 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
utiliza gets(), por lo que
es susceptible a un ataque de desbordamiento de ‘buffer’.
El ‘buffer’ tiene un tamaño de 54 bytes y, conforme al nombre de la variable local_3e en ‘Ghidra’, la dirección de retorno de la función se encontraría desplazada 0x3e (62) bytes desde la dirección de inicio del ‘buffer’.
Asimismo, veo que hay una función systemFunc() a la que no se llama nunca:
En esta función
se realiza una llamada a system() con argumento iVar1 +
0x12e, es decir,
la llamada que se realiza es: system(“/bin/sh”) (ver explicación en este
post), lo que me permitiría obtener una
‘shell’ en el servidor.
Por tanto, mi plan de ataque consiste en sobrescribir la dirección de retorno de la función vuln() con la de inicio de la función systemFunc(), con lo que se obtendrá una ‘shell’, se podrá buscar y ver la flag, y, en consecuencia, se resolverá este reto.
Tal y como he dicho anteriormente, la dirección de retorno de la función vuln() se encontraría con un desplazamiento de 0x3e bytes desde la dirección de inicio del ‘buffer’, con lo que el tamaño del relleno de la cadena que debo incluir antes de la dirección de inicio de la función systemFunc() es de 62 bytes.
Para implementar el ataque
creo un pequeño ‘exploit’ mediante un ‘script’ en python para que envíe 62 bytes (0x3e) de relleno y luego la dirección de inicio de la función
systemFunc(), con lo que sobrescribiré la dirección de retorno de la función
vuln() con la anterior, se bifurcará a la función
systemFunc() y se abrirá una
‘shell’:
#!/usr/bin/env python3
from pwn import *
binary = ELF('./chall_13')
p = remote('chal.2020.sunshinectf.org', 30013)
p.sendlineafter('Keep on writing\n','')
payload = b'A' * 0x3e
payload += p32(binary.sym.systemFunc)
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{almost-easy-61ddd735cf9053b0}
Comentarios
Publicar un comentario