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.

Prueba del formato

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:

Prube de la pila

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):

Obtención de la bandera

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 :(