漏洞分析 CVE-2010-0249
漏洞分析 CVE-2010-0249
简单的简单 看雪学苑 2023-11-25 17:59
漏洞编号:CVE-2010-0249
危害等级:高危
漏洞类型:缓冲区溢出
操作系统:Windows 2000/XP/2003/Vista Gold/2008/7/
软件名称:Internet Explorer
软件版本:6.0
漏洞模块:mshtml.dll
模块版本:6.0.2900.5512
物理机(或者单独开一个虚拟机作为服务端)开启 IIS 服务作为网站服务器。
开启 IIS
◆控制面板 — 程序和功能 — 启用或关闭 Windows 功能
开启 Internet Information Services:
开启 Web 管理工具下所有选项;
开启万维网服务下所有选项。
开启 .NET Frameword 3.5 下所有选项。
◆控制面板 — 管理工具 — Internet Information Services (IIS)管理器(注意不是6.0的那个)
计算机名 — 网站 — Default Web Site — 启动(在最右边) — 浏览 *:80(http) — 此时应可以正确访问 windows 的测试网站。
Default Web Site — 右键 — 编辑绑定 — 添加 — IP地址填写本机 IP — 端口这里使用 80。
此时会发现浏览器中可以使用访问 localhost 访问页面,但无法使用刚才设置的 IP 访问,其实是还需要配置入站规则。
笔者在操作到这一步时还遇到一个错误,提示文件夹XXX无法写入,经检查根本没有这个文件夹,笔者根据提示手动创建了这个文件夹,并给与了 EveryOne 权限后不再提示该错误。
控制面板 — 防火墙 — 高级设置 — 入站规则 — 新建规则 — 端口 — 特定本地端口 — 80 — 允许连接 — 默认勾选域、专用、公用 — 名称设置为 IIS 规则即可 — 完成(如果是在虚拟机里搞可以直接把防火墙关了就行)。
再次在浏览器使用 IP 访问页面可以发现已经可以正确访问了,至此 IIS 已正确启动,下面开始搭建本次使用的服务器。
Internet Information Services (IIS)管理器 — Default Web Site — 停止。
Internet Information Services (IIS)管理器 — 网站 — 添加网站 — 设置网站名称 — 设置网站路径 — 设置网站IP为本机IP — 设置端口为80 — 完成。
将 poc.html 文件拷贝到网站路径中。
再次在浏览器使用 IP+poc.html 访问页面可以发现已经可以正确访问。
安装虚拟机
虚拟机使用 window xp sp3,建议从msdn下载镜像自己安装,笔者最开始用的别人做好的windows xp sp3 虚拟机 POC 无法正常运行,这里附上MSDN中的镜像版本 Windows XP Professional with Service Pack 3 (x86) – CD (Chinese-Simplified)。
启动windbg并配置符号文件,使用 windbg 附加 IE 浏览器,执行 pochttp://192.168.0.113/Aurora.html?rFfWELUjLJHpP
,等待windbg 断在mshtml!CElement::GetDocPtr+0x2:
处,需要注意该 poc 的堆喷射并非每次都可以成功,如未在此处断下建议多尝试几次,如正确断下则代表漏洞已复现成功,此时可在 windbg 中使用命令.dump -ma dumpfile.dmp
将异常信息全部 dump 到文件中,dumpfile.dmp 文件保存在 windbg 软件所在的目录中。
可以通过栈帧,回溯漏洞的调用流程。
在 IDA 中查看地址 7e44c4c8 处代码,因为异常断在 7e278c85 处,所以显然是 7E278C83 的mov eax[ecx]
出现问题,因为这只是一条 mov 指令,所以异常必然是对 ecx 解引用导致的,也就是说此时 ecx 的值是非法地址,为了清晰的观察 ecx 的值的传递过程,此时我们将 ecx 的值标记位 leak,我们倒着推一下 leak 这个值是怎么来的。
通过栈回溯,在IDA中跳转到地址 7E44C4BE,此时我们容易推出下列结论,leak = [esi]。
继续向上回推,会发现 esi = [eax+n],eax = [ebp + var_8],此时我们暂且认为n为0,即 leak = [[eax]] = [[[ebp + var_8]]] 显然接下来我们需要关注 var_8。
继续向上推会发现其调用了函数 GetParam@CEventObj,而这个函数将 [ebp+var_8] 作为唯一参数,显然我们需知道这个函数中是否对 [ebp+var_8] 的值进行了修改,因为是作为参数压入了栈中,下面的代码中我们需要关注的其实是 [ebp+8],通过简单的代入可得到:[[参数1]] = this + 0x18。
回到调用 GetParam@CEventObj 函数处,可以轻松推导出 [[eax]] = this + 0x18,结合之前的推论 leak = [[[ebp + var_8]]],可得到最终推论 leak = [this+0x18]。
而函数 GenericGetElement 的 this 也就是 ecx 是由外界参数传入的,也就是说这个地址是可控的。
前置知识
◆setInterval:可按照指定的周期(以毫秒计)来调用函数或计算表达式,setInterval方法会不停地调用函数,直到 clearInterval被调用或窗口被关闭。window.setInterval(调用函数,延时时间)。
◆event.srcElement:可以捕获当前事件作用的对象。
◆document.createElement:动态创建DOM元素并插入的已有的HTML中,函数接受一个HTML标签名称并返回Element 类型的新节点。
◆unescape:可对通过 escape() 编码的字符串进行解码。
POC解密
为了便于分析,我们不希望程序直接被执行,而是想看一下解密后的代码是什么,而解密后的代码保存在变量“NqxAXnnXiILOBMwVnKoqnbp”里面,我们可以先将上述代码注释掉,在它上面添加这样的一行代码,这里结合console.log() 方法可以将解密后的内容在控制台输出,使用浏览器执行这个网页文件,打开开发者模式中的控制台就可以看到解密后的内容了。
逐步分析
1.onload 中调用 WisgEgTNEfaONekEqaMyAUALLMYW(event)
2.该函数中分别执行了堆喷射、创建事件对象、释放iframe、延时调用
3.重点在延时调用的函数,在这个函数中覆盖了虚表指针,导致再接下来的调用时
尽管已经定位到了导致崩溃的位置以及函数的调用情况,但是我们还是要进一步探索出现漏洞的根本原因的,所以有必要研究一下IE浏览器在解析这个PoC网页的时候到底出现了什么情况。
通过刚才的分析我们知道,程序一开始调用了document.createEventObject为当前的event事件创建一个副本,因此我们不妨使用WinDbg的x命令来检查调试符号,这里可以找到两条结果,其中地址为0x7e216b2c的内容通过IDA查看,发现它是一种数据结构,所以程序只可能使用CDocument::createEventObject用于解析JavaScript代码中的document.createEventObject函数。所以不妨在IDA中来到0x7e383b3b位置分析一下副本的创建方式。来到该函数的末尾,可以发现它的主要功能是由CEventObj::Create来实现的。
在IDA中跳转到 7e383b3b,转换为伪代码后可以发现,实际调用的是 CEventObj::Create。
在 CEventObj::Create 中在申请堆空间后,会调用函数 EVENTPARAM::EVENTPARAM。
在分析 EVENTPARAM::EVENTPARAM 函数前先补充一下 EVENTPARAM 结构的知识。
分析函数 EVENTPARAM::EVENTPARAM 可以看到,这个函数将参数二的数据拷贝到 this指针处,但是请注意,参数二中还包含着一个叫做CTreeNode的对象结构体,此处将CTreeNode对象拷贝,但是没有将CTreeNode的引用计数加一。
我们已经弄清了漏洞的成因,所以我们尝试在windbg中观察漏洞的形成过程,看看事件对象是如何创建和保存的。其实在mshtml模块中是存在有一个用于创建不同元素的函数表的,它的地址是 7e21aa98。
在这个函数表中我们可以找到创建IFrame的函数,它的地址是 7E21ADC0。
回到虚拟机中在函数上下断点。
这里所获取的CIFrameElement对象指针会保存在ecx寄存器中(利用IDA结合上下调用关系可以得知),也就是地址为0x01ca1710的位置,但由于现在还没有开始创建,因此这个地址中并没有内容。
然后我们在CTreeNode上也下一个断点,并通过栈回溯来观察一下。
在这里,CTreeNode已经将刚才的CIFrameElement对象指针当作自己的第二个参数使用了。同时利用CTreeNode::SetElement函数将CIFrameElement类与CTreeNode相关联。此时可以再看一下0x01ca1710中的内容并进行解引用:
此时查看 7e25bc68 处可以看到,该指针最终指向的是“vftable”。
如果在我们之前提取出来的dump文件中,查看原本指向虚表的指针,即0x01ca1710位置,则可以看到如下数据:
在创建CEventObj时,会创建EVENTPARAM结构,如果新创建的CEventObj是从已有的CEventObj继承而来时,则这两个CEventObj事件的源相同。在新创建的EVENTPARAM结构的偏移0处的元素pNode(CTreeNode),将复制源CEventObj该处的值。
在补丁前,上述过程没有增加CTreeNode的引用计数,在精心构造的html中,有可能导致CTreeNode已经释放,而EVENTPARAM的pNode却仍然指向它,导致释放后重用。
补丁后,在EVENTPARAM::EVENTPARAM中,对上述情况作了处理,增加CTreeNode的引用计数,不会再导致问题。
看雪ID:简单的简单
https://bbs.kanxue.com/user-home-950902.htm
*本文为看雪论坛优秀文章,由 简单的简单 原创,转载请注明来自看雪社区
#往期推荐
1、2023 SDC 议题回顾 | 芯片安全和无线电安全底层渗透技术
6、2023 SDC 议题回顾 | 深入 Android 可信应用漏洞挖掘
球分享
球点赞
球在看