Heap Exploitation系列翻译-08 First Fit

| categories translations  | tags CTF  pwn  heap 

First-fit behavior

本文是对Dhaval Kapil的Heap Exploitation系列教程的译文

这项技术描述的是glibc分配器的’first-fit(优先匹配)’行为. 无论何时堆块(除开fast chunk)被释放, 都会加入到unsorted bin中, 插入到列表的首部. 当申请新堆块(再次申明,除开fast chunk), 在一开始会查找unsorted bins因为此时small bins还是空的. 查找操作从链表尾部进行, 如果unsorted bin中存在一个简单的堆块, 就不会进行精确的检查并且当堆块大小大于等于申请大小, 就会切成两半并返回. 也就确保了先进先出的行为.

考虑以下示例代码:

char *a = malloc(300);    // 0x***010
char *b = malloc(250);    // 0x***150

free(a);

a = malloc(250);          // 0x***010

unsorted bin的变化状态如下:

  1. ‘a’ freed.
      > head -> a -> tail
    
  2. ‘malloc’ request.
      > head -> a2 -> tail [ 'a1' is returned ]
    

堆块’a’被切成两个堆块’a1’和’a2’, 这是因为所申请的大小(250 bytes)小于堆块’a’的大小(300 bytes). 这符合_int_malloc中的[6. iii.]

在fast chunks情形下也是如此, 只是堆块释放后不会添加到unsorted bin中而是fastbins. 就如早先提及的那样, fastbins是一个单向链表并且堆块的插入删除操作都在链表首部进行, 这刚好跟获得堆块的顺序相反.

考虑以下示例代码:

char *a = malloc(20);     // 0xe4b010
char *b = malloc(20);     // 0xe4b030
char *c = malloc(20);     // 0xe4b050
char *d = malloc(20);     // 0xe4b070

free(a);
free(b);
free(c);
free(d);

a = malloc(20);           // 0xe4b070
b = malloc(20);           // 0xe4b050
c = malloc(20);           // 0xe4b030
d = malloc(20);           // 0xe4b010

fastbin的状态变化如下:

  1. ‘a’ freed.
      > head -> a -> tail
    
  2. ‘b’ freed.
      > head -> b -> a -> tail
    
  3. ‘c’ freed.
      > head -> c -> b -> a -> tail
    
  4. ‘d’ freed.
      > head -> d -> c -> b -> a -> tail
    
  5. ‘malloc’ request.
      > head -> c -> b -> a -> tail [ 'd' is returned ]
    
  6. ‘malloc’ request.
      > head -> b -> a -> tail      [ 'c' is returned ]
    
  7. ‘malloc’ request.
      > head -> a -> tail           [ 'b' is returned ]
    
  8. ‘malloc’ request.
      > head -> tail                [ 'a' is returned ]
    

The smaller size here (20 bytes) ensured that on freeing, chunks went into fastbins instead of the unsorted bin.

我们使用了一个比较小的size(20 bytes)来确保堆块释放后会添加到fastbins中而非unsorted bin

Use after Free Vulnerability

在上述例子中, 我们可以看到, malloc 可能 会返回我们早先使用并释放掉的堆块. 这也就导致当使用已释放的内存堆块会造成漏洞. 一旦一个堆块被释放, 也就可以假定攻击者现在能控制堆块中的数据. 这块堆块不应该被再次使用, 相反我们应该经常申请新的堆块.

看看示例的漏洞代码片段:

char *ch = malloc(20);

// Some operations
//  ..
//  ..

free(ch);

// Some operations
//  ..
//  ..

// Attacker can control 'ch'
// This is vulnerable code
// Freed variables should not be used again
if (*ch=='a') {
  // do this
}

Previous     Next