Home > Exploit Writing, Uncategorized > Explotación de Format String Bugs

Explotación de Format String Bugs

Hoy le llego la hora al Exploit Writing, un tema que me encanta pero por falta de tiempo siempre lo tengo que dejar de lado. Hoy vamos a hablar de un tipo de bugs de la que todos han escuchado hablar, pero pocos saben explotar.

Se trata de los conocidos format string bugs. Estos errores son explotados desde la edad de piedra, pero siempre esta copado aprender algo que no se conoce, así que acá voy a ir anotando mis avances. Encima si ayudo a alguien aunque sea un poco a que entienda esto… entonces doble felicidad.

Antes de comenzar la explicación, voy a pegar una imagen que encontre aca, ese dibujito, resume muy bien cual es el bug 😉

La mayoría de los textos que van a encontrar dando vueltas por internet sobre este tema, explotan todo en Linux y usan el espartano gdb para analizarlo. Encima en ese tiempo no existia la tecla “Impr Pant” por lo tanto no encontras una captura de pantalla ni de suerte :-P.

Vamos a comenzar con un típico programa vulnerable de prueba, para entender la cosa:

#include <stdio.h>

char cookie;

int main(int argc, char **argv) {
char *p;
p = &cookie;
printf(argv[1]);

if(cookie == (char)0xFE) {
printf("\n[+] You are a great exploit writer\n");
} else {
printf("\n[-] -1 for you\n");
}
return 0;
}

Un programa muy simple, definimos una variable cookie a la cual no le asignamos ningún valor, pero la misma es comparada con un valor (0xFE), si es igual te imprime el good boy, sino el bad boy.

Antes de adentrarnos donde esta el error, vamos a comenzar viendo el programa:

nos imprime el primer argumento que le escribamos y después nos tira un mensaje negativo porque cookie no tiene el valor que el quiere. Antes de adentrarnos de lleno en el reto, vamos a tratar de entender la vulnerabilidad.

printf(argv[1]);

si vemos cualquier llamada a printf, vamos a tener algo como lo siguiente:

printf("Su numero es %d\n", numero);

el %d es una cadena de formato. Escaparía de los objetivos de este post si me pongo a explicar que es eso, para ello pueden visitar wikipedia.

Solo decir, que eso en ensamblador se traduciría a algo mas o menos así:

push 200.
push DWORD PTR[404000]; ASCII "Su numero es %d\n"
call <&jmp.msvcrt.printf>

Esto es a modo explicativo, en realidad el 200 seria una variable, pero para que se entienda esta bien 💡

En nuestro programa no estamos definiendo la cadena de formato, por lo tanto nosotros tenemos el control de como se imprimen las cosas. Hagamos una prueba:

apaa, %.8x lo tomo como una cadena de formato (un numero hexadecimal de 8 caracteres de largo relleno con 0’s) y agarro lo próximo que había en el stack. Esto es lo que hay que entender, tómense el tiempo necesario para tratar de asimilar este caso y después siguen.

La cadena de formato, le esta diciendo al printf de que hay un segundo argumento aunque este nunca aya sido pusheado. Eso significa que estamos leyendo direcciones del stack. Con lo cual tenemos a nuestra disposición cualquier cosa que aya este. Tales como las direcciones de retorno, los ebp o las direcciones de las variables.

Juguemos un poco para imprimir algún RET que encontremos en el stack.

ahí lo tenemos. Vemos como nos devolvió el valor de la RETURN ADDRESS, del mismo modo podríamos haber obtenidos valores de variables o cualquier cosa que se nos ocurra en nuestra intrincada imaginación.

Aprenderemos como escribir valores en la memoria del programa para poder hacer algo mas divertido que mirar.

Para esto vamos a hacer uso del format code %n, yo al decir verdad no lo conocía hasta el día de hoy. Si miramos las man page de printf, dice lo siguiente sobre el %n:

%n: The number of characters written so far is stored into the integer indicated by the int * (or variant) pointer argument. No argument is converted.

Pasándolo en limpio para la muchachada, guardara la cantidad de caracteres que escribió hasta el momento en la dirección que le pasemos. Esto es lo que vamos a usar para poder controlar los valores de las variables.

Echemos un ojito para ver como esta el stack al momento que nosotros lo podemos toquetear, para ver que es lo que podemos hacer.

Este es el reto, modificar el valor de la variable cookie (direccion 404010) desde este bug, antes tenemos que llegar hasta ese argumento rellenando con los %.8x. En realidad funcionaria cualquier cosa como un %d, pero se usa %.8x para tener un control preciso de la cantidad de bytes que se imprimen, ya que despues lo tenemos que tener en cuenta para explotar la vulnerabilidad.

Una vez que llegamos al puntero en el stack usamos %n para que escriba el tamaño de la cadena formateada (hasta encontrarse con el %n).

Como una imagen vale mas que mil palabras, vamos a los echos:

ahora ejecutemos el printf con F8 y miremos que tiene 404010

%n escribió en 404010 el numero 72, que corresponde con la cantidad de caracteres formateados al momento de encontrarse con el código de formato “n”. En este caso concuerda con lo devuelto por la función por el echo de que %n es el ultimo caracter en la cadena, pero esto no siempre es asi, y lo veremos en las proximas explotaciones.

Bueno, vallamos a la comparación, haber que nos dice

ahí lo tenemos, compara nuestro 0x48 con su 0xFE, entonces lo único que tenemos que hacer es escribir 0xFE bytes con la cadena de formato, para que guarde esa cantidad en 404010. 0xFE en decimal es

entonces, solo tenemos que a 254, restarle el tamaño que ya tenemos para que obtenga ese valor. Asi dejariamos el 0xFE en nuestra variable.

Ahora vamos a explotarlo, obteniendo el valor necesario en la variable

Ahí esta, ahora miremos como queda todo probandolo sin el debugger:

Obtuvimos nuestra recompensa, logramos explotar nuestro primer format string bug. En breve sacare otro post tratando explotaciones cada vez mas difíciles, y viendo que problemas nos podemos encontrar.

Saludos

  1. No comments yet.
  1. No trackbacks yet.

Leave a comment