Write-ups del Ciberseg '17: exploiting
Estos son los retos de exploiting que formaron parte del CTF organizado en el Ciberseg 2017, un congreso sobre ciberseguridad que tiene lugar cada año en nuestra universidad.
El año pasado fue la primera edición (y espero que haya más, pues fue bastante divertido) del CTF (y yo gané el primer premio :D).
Primer reto: Buffer overflow
Desafortunadamente, perdí perdí los datos de este reto; así que no puedo escribir sobre ello :(
Segundo reto: Format string
Materiales
Para este reto, nos dieron la dirección de un servidor que estaba ejecutando un programa, y el código fuente del mismo.
El código fuente puede ser descargado aquí. Para compilarlo, simplemente hay que ejecutar gcc -m32 format-main.c
,
y asegurarse de desactivar el Adress Space Layout Randomization (el reto sigue siendo
posible con el ASLR activado, pero es más fácil desactivándolo) ejecutando
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
.
El reto
Ahora, tras obtener el código, podemos empezar a examinarlo. La primera cosa interesante
que notamos es que, en la función upcase ()
, la entrada es impresa por pantalla sin
tratar; así que podemos simplemente escribir algunos caracteres extraños, como ‘%’ e
inyectar formatos y hacer cosas malas con ello.
Las líneas marcadas son las importante, donde la cadena de entrada es manipulada y la repite de vuelta:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void upcase(void) {
char str[512];
char *upcase_str;
int i;
puts ("Introduce la cadena que va a ser convertida (max 500 caracteres):");
PROMPT;
fflush (stdout);
==> fgets (str, 500, stdin);
str[strlen (str) - 1] = '\0';
printf ("Has introducido: ");
==> printf (str);
puts ("");
upcase_str = (char *)calloc (strlen (str) + 1, sizeof (char));
strncpy (upcase_str, str, strlen (str));
for (i = 0; i < strlen (upcase_str); i++) {
upcase_str[i] = toupper (upcase_str[i]);
}
printf ("El resultado: %s\n", upcase_str);
free (upcase_str);
}
Para comprobar esta hipótesis podemos insertar alguna cadena de formato como ‘%08x’, que imprimirá los 4 Bytes (8 caracteres) de la representación hexadecimal, rellenada con ceros, del argumento.
Como no le hemos dado ningún argumento, se coge el primer elemento de la pila.
Ahora podemos controlar la pila. Para probarlo y comprobar los valores que hay en la
pila, podemos intentar sacar un valor de la cima (como ‘AAAA’, o 0x41414141, un valor
fácilmente reconocible). Por ejemplo, sacamos 10 valores de la pila con la entrada
AAAA_%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x
:
Lo que está pasando aquí es que estamos añadiendo ‘AAAA_%08x.%08x.%08x.%08x.%08x.%08x .%08x.%08x.%08x.%08x’ en la pila; pero, con cada cadena de formato, la función saca un elemento de la pila, interpretándolo como un elemento a ser formateado.
Finalmente, podemos explotar esto para leer cualquier dirección que queramos. Para ello, podemos simplemente usar la cadena de formato ‘%s’, que saca un elemento de la pila y lo interpreta como la dirección de la cadena a ser mostrada.
Podemos obtener la dirección de la bandera usando el comando flag
, donde nos dice que
la bandera está en 0x0804c008 (si desactivamos el ASLR, esta dirección será siempre la
misma; pero con él activado no es tampoco mucho más complicado que leer el valor y
cambiar el exploit de manera acorde), y sabemos que debemos sacar 7 elementos de la
pila hasta que podamos inyectar cualquier valor. Podemos desarrollar ahora el exploit.
El exploit es construido simplemente cambiando el ‘AAAA’ por la dirección de la bandera (en little-endian) y el séptimo ‘%08x’ por un ‘%s’. Este exploit no puede ser escrito directamente, porque no podemos escribir el valor ASCII de \x08\xc0\x04\x08 con el teclado. En su lugar, podemos usar un archivo auxiliar (los comandos mostrados son ejecutados en una shell POSIX):
En la competición tuvimos que explotar una instancia de este programa en un servidor, con
una bandera diferente (a la cual no teníamos acceso, obviamente), pero la metodología
para explotarlo sigue siendo la misma (sustituyendo cat exploit - | ./a.out
por
cat exploit - | nc <dirección-servidor> <puerto-servidor>
).
Al final, tenemos nuestra bandera: flag {9e0480fa680754a7286b9686ce606f22}
.
Tercer reto: casino
Como en el primer reto, perdí los materiales para este reto; así que no puedo escribir la solución :(