查看原文
其他

CVE-2012-1875简单分析

luobobo 看雪学院 2019-05-26

在IE漏洞中,UAF是广为存在的,所以这一次想调试学习一下这类型的漏洞,也熟悉了解一些IE的机制。如有错误或意见,还请斧正和提出,感激不尽。


调试环境


Windows7 sp1 x86

IE8.0.7601.17514


修改过后的简易POC:

<html>

<body>

<title></title>

<DIV id=testfaild>
   <img id="test">
   <div id="test"></div>
   <input id="what" onMouseOver="crash();"></input>
</DIV>
 
<script language="JavaScript">
function crash() {
   test.src = "";
}
 
function trigger() {
   Math.tan(0);
   var x = document.getElementsByTagName("input");
   Math.tan(0);
   x[0].fireEvent("onMouseOver");
   Math.sin(0);
   testfaild.innerHTML = testfaild.innerHTML;
   Math.cos(0);
   x[0].fireEvent("onMouseOver");
}
trigger();
</script>

</BODY>

</HTML>

打开PoC后,崩溃信息如下:




看来是某个Element释放后重用所导致的。IE在解析DOM树的过程中会使用CCollectionCache结构将所创建的元素缓存以加速查询,在第一次执行crash函数时,CCollectionCache::GetDisp 会调用CCollectionCache::BuildNamedArray、CMarkup::AddToCollections 来函数遍历HTML页面中所有具有id属性的标签在内存中的对象,创建一个具有"test"id属性的对象所组成的数组,通过 CImplPtrAry::Copy 将上述数组保存至新创建的CElementAryCacheItem 对象中。




打开Windbg附加进程,下如下断点:




运行后断在断点0处,在IDA加载符号表后找到mshtml.dll中CCollectionCache::CCollectionCache



在Windbg单步执行完该函数,查看CCollectionCache对象




第一次断在tan语句时,查看CCollectionCache对象(05b7dfd0即为上文中esi的值)




可以看到其保留的数组大小为0x0d,先来查看Index 0




接着需要重点关注Index 8中对应元素CElementAryCacheItem中的内容:




可以看到其ArraySize为4,




对应着我们在PoC中定义的对象。


接着我们在开始提到的,在第一次执行crash函数时,会创建一个具有"test"id属性的对象所组成的数组,数组会保存在Index e处。在执行之前,我们先来看看那里现在的情况。(在两个tan语句中间获取input对象时,CCollectionCache结构体中Item数组大小及首地址均变化,因重复打开后地址随机化,故此处0720dfd对应着之前CCollectionCache对象的地址)




(当执行 getElementsByTagName 语句且在 CImplPtrAry::Copy 断下时,可以自己试试找找准备拷贝的id为input的对象数组,此处略)


在执行tan与sin之间的crash函数时,代码在 BuildNamedArray 函数之后断在 CImplPtrAry::Copy 处,在Index e处新建了一个CElementAryCacheItem 待赋值。




可以发现此时ecx中保存着新 CElementAryCacheItem 对象地址,DWORD PTR[EAX+C] 中保存着被拷贝的id为“test”对象数组:




单步执行至 CImplPtrAry::Copy 函数结束后,新 CElementAryCacheItem  完成赋值。


sin与cos之间,语句 testfailed.innnerHTML=testfailed.innnerHTML 会使得当前页面中所有标签在内存中的对象被销毁,并依次重新创建相关类型的对象。所以当执行过该语句后,CollectionsCacheItem 数组Index E位置上的NewCacheItem中保存的已经是被释放了的对象的内存地址。




当PoC中第二次调用crash函数时,会使用GetDispID查询对应的元素是否需要重建。在IDA中可以得到GetDispID的堆栈调用:

CCollectionCache::GetDispID

    CCollectionCache::EnsureAry

    CCollectionCache::GetIntoAry

        CCollectionCache::GetAtomFromName


http://zenhumany.blog.163.com/blog/static/1718066332013926101149471/中提到“在CCollectionCache::EnsureAry中会对查询的CatchItem是否有效进行验证,验证的方法是(见下图):



其当前的版本lCurrentVersion和它引用的原始的CacheItem的版本是否一致,如果不一致,需要根据原始版本重新构建给定的CacheItem。”

最终在本PoC中,程序会再次读取已释放的CCollectionCache Index e处的CElementAryCacheItem,造成异常。


参考目录



  • http://zenhumany.blog.163.com/blog/static/1718066332013926101149471/


  • https://bbs.pediy.com/thread-152240.htm






本文由看雪论坛 luobobo 原创

转载请注明来自看雪论坛



往期热门阅读:


扫描二维码关注我们,更多干货等你来拿!



    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存