Código:
printf("Te paso %d %s",2,"argumentos");
En base a los símbolos con "%"(salvo excepciones), printf sabe cuántos argumentos se le han pasado y por lo tanto cuán profundo tiene que buscar en la pila. Bueno, ahora dejemos que el texto formateado lo ingrese el usuario:
Código:
//char *fmt="Soy el usuario con %d %s"; <-- establecida por el usuario
printf(fmt,2,"argumentos");
printf(fmt,2,"argumentos");
Acá aparece la vulnerabilidad, puesto que el usuario le podría pasar más modificadores, por ejemplo "Soy el usuario con %d %s %x %x %x". De este modo printf va a creer que tiene más argumentos de los que en realidad se le pasan e intentará buscarlos.
De esta forma podríamos hacer un volcado de pila por ejemplo:
Código:
char fmt[]="Volcado de pila %d %s %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n";
char str[]="argumentos.";
int a=2;
printf(fmt,a,str);
char str[]="argumentos.";
int a=2;
printf(fmt,a,str);
Por otro lado, si se desea indagar en ciertos lugares de la pila sin necesidad de hacer un volcado completo se puede utilizar el modificador "%m$", donde m es un entero que indica el número de argumento a tomar.
También se pueden leer direcciones específicas de memoria(si son accesibles), con la restricción de que no pueden haber ceros(de tamaño byte) ya que al fin y al cabo la dirección que queremos leer se la debemos pasar por medio de la cadena fmt. La idea consta en llegar por medio de "%m$s" al comienzo de la cadena ingresada, que fue almacenada en la pila, y en el comienzo escribimos la dirección que deseamos leer. Ejemplo:
Código:
char fmt[]="\xf0\xff\xff\xbf %100$s";//ver por argumento 100 = comienzo de fmt
...
printf(fmt,a,str);
...
printf(fmt,a,str);
Por supuesto que no es necesario colocar la dirección a leer exactamente en el comienzo de la cadena, lo que si es necesario es que debe estar alineada, o sea en direcciones múltiplos de cuatro en arquitecturas de 32bits; por esta razón a veces se debe agregar basura para lograr la alineación.
Y como no iba a ser la excepción, también podemos escribir en memoria. Para ello tenemos el modificador "%n", donde el número de caracteres escritos a la salida hasta que se alcanzó "%n" se guarda en el entero indicado por el argumento de tipo puntero int* (o una variante suya). O sea que para escribir el valor 1000 se deben colocar 1000 caracteres basura en la cadena precediendo a "%n"; para evitar esto podemos cambiar el ancho de la salida. Para el ejemplo citado basta hacer "%.1000x%n".
Pero se presenta otro problema, muchas implementaciones de la librería estándar de C no pueden manejar especificadores de ancho demasiado grandes. Entonces para escribir un valor muy grande vamos a tener que hacerlo de a poco, byte por byte. Vamos a suponer que queremos escribir el valor 0x806a4431 en la dirección de memoria 0xbfffff50, y que nuestra cadena formateada en la pila se alcanza en el argumento 100. Entonces:
1- "%x.49%100$hn" -> 31000000 (49=0x31)
2- "%x.19%101$hn" -> 44000000 (49+19=68=0x44)
3- "%x.38%102$hn" -> 6a000000 (49+19+38=106=0x6a)
4- "%x.22%103$hn" -> 80000000(49+19+38+22=128=0x80)
5- "%x.49%100$hn%x.19%101$hn%x.38%102$hn%x.22%103$hn" -> 31446a80 (0x806a4431 en notación little endian)
Las direcciones a las cuales queremos escribir podemos ponerlas al final(o al inicio, sólo hay que tener en cuenta el largo de la cadena que tomará "%n" así como también el número de argumento con el cual son alcanzadas), por lo tanto primero escribimos en 0xbfffff50(argumento 100), luego en 0xbfffff51(argumento 101), en 0xbfffff52(argumento 102) y por último en 0xbfffff53(argumento 103).
En resumen, es posible armar un cadena tal que escriba un valor arbitrario en una dirección de memoria arbitraria. Justamente si lo que se desea es ejecución de código propio, escribimos la dirección de retorno con el valor de la direción donde se almacena nuestra shellcode. La mayor parte de la información para escribir este texto la saqué de www.securityfocus.com. Les recomiendo que lean este documento para mayor información:
http://downloads.securityfocus.com/library/format-bug-analysis.pdf.
Espero que les sea de utilidad a todos.
Bytes.










Autor



En línea







. 



