Protostar-堆溢出学习-滥用堆metadata重定向程序执行

By xia0

0x00 序

学习最后一个堆溢出漏洞,在这之前,强烈建议先阅读下我之前对linux堆管理DLMalloc的分析这是一个滥用堆metadata导致free()函数造成任意地址写的一个漏洞利用。下面一步一步的分析

0x01 C语言源代码

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

void winner()
{
  printf("that wasn't too bad now, was it? @ %d\n", time(NULL));
}

int main(int argc, char **argv)
{
  char *a, *b, *c;

  a = malloc(32);
  b = malloc(32);
  c = malloc(32);

  strcpy(a, argv[1]);
  strcpy(b, argv[2]);
  strcpy(c, argv[3]);

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

  printf("dynamite failed?\n");
}

0x02 简单分析&思考

在这个程序中虽然我们知道有堆溢出的问题,可是堆上并没有什么逻辑上的漏洞,没有可利用的指针?没有UAF漏洞?那怎么才能执行到winner()函数呢?似乎是不可能的事。但通过之前对linux堆管理的分析,可知free()函数中的unlink()函数能够造成一个任意地址写的可能,再像之前那样来修改GOT表,不就是可以执行winner()函数了吗?所以要执行unlink()函数就需要构造两个chunk合并的过程,继而将一个chunk从原来的双链表中unlink下来。
就照着这个思路来一步步实现这个过程。

0x03 调试

1.输入AAAA BBBB CCCC然后free前后后观察堆结构
0-0
由上图可得,一共有三个分配的chunk,大小都为29(101001)末位表示前一个chunk正在使用。可以看到最后还有一个很大的chunk,这就是上文所指的topchunk。
0-1
因为chunk的大小<80字节,所以free后存在单链表的fastbin中,`1-->2–>3–>null`的方式连接

2.因为需要unlink一个chunk到双链表bin,所以先覆盖掉第三个chunk让其大小为0x64=100字节。
0-2
因为我们准备向前合并,所以将preinuse位设为1,即64+1=65

3.然后还需要构造一个假的chunk让其unlink,这个chunk将精心构造,首先fd=GoT地址 bk=winner地址?等等,这里存在一个问题在于:GoT=winner地址,但winner=GoT在会发生段错误,所以这里有个小技巧在于bk=堆地址,GoT-12=堆地址,然后堆中填上shellcode,去调用winner。
构造字符串:
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\xfc\xff\xff\xff\xfc\xff\xff\xff\x1c\xb1\x04\x08\x0c\xc0\x04\x08
0-3

4.现在我们需要构造shellcode,因为堆地址+16字节出会写入GoT地址,所以我们的shellcode要足够小,正好我们仅仅需要调用winner而已。
0-4
这里我们用在线的转换工具下面的汇编转化为x86指令字符串

mov eax,0x8048864
call eax

0x8048864为winner()函数地址

5.将上面的shellcode写入第一个chunk那里,here we hack!
0-5
下图可以看到shellcode后面就被填入了GoT地址,也说明了shellcode只能为8字节大小。
0-6
GoT地址已经修改,下面可以看到已经执行了winnwe()函数
0-7

0x04 一点补充

在上面构造chunk中,也许你已经发现了chunk大小为0xfffffffc,这是一个什么巧妙的方法去绕过free()里面的检查等。具体的细节可以看
Once upon a free()这篇文章,简单的说就是当某个数加上0xfffffffc时会造成溢出相当于减4从而使其向前偏移4个字节,绕过检查,避免崩溃。

0x05 堆漏洞学习总结

目前可能这是最后一个堆漏洞的学习,这个堆漏洞的学习理解到动手前后花费了大量时间,不过这都是值得的,如果能够坚持下来,将会对堆漏洞有一个清晰的认识。以后再遇到漏洞或者别人的分析能够快速准确的理解。虽然现在堆管理代码经过了很多改善和patch,但基本和关键的技术还是没变。所以keep hacking!