极光行动漏洞分析-漏洞成因分析
1. 前言
上一篇文章对流量包进行了分析,提取出了攻击样本,这次接着对漏洞成因进行一次详细分析。
2. 漏洞详细分析
2.1 查看崩溃信息
首先访问提取的攻击样本,使IE
崩溃:
从崩溃信息来看,崩溃位置在mshtml.dll
模块中偏移0x68C83
的位置
UAF
漏洞,在空间被释放后,那一片区域的内存空间可以被任意使用的,而堆喷的内容有可能会被程序运行过程中给覆盖掉,所以会导致漏洞利用失败,需要多次尝试2.2 windbg查看详情
通过windbg
附加调试,可以看到是在CElement::GetDocPtr
这个函数产生了崩溃:
从上图可以看到,崩溃原因是因为ECX
的值为0x00000054
,而从[ECX]
中取值产生了访问异常,那么ECX
的值是哪来的呢?
mshtml.dll
文件的符号文件,是显示不出来函数名称的2.3 windbg栈回溯
通过windbg
进行栈回溯,如下:
从栈回溯中,可以看到调用CElement::GetDocPtr
的位置是CEventObj::GenericGetElement
函数和CEventObj::get_srcElement
函数
2.4 ECX寻找
从后往前分析,首先分析CEventObj::GenericGetElement
。将mshtml.dll
拖入IDA Pro
并且定位到CEventObj::GenericGetElement
函数(需要符号文件支持),找到调用CElement::GetDocPtr
的位置,如下图:
从上图可看到,调用CElement::GetDocPtr
之前,ECX
的值来自EBX
,而EBX
又是从[ESI]
所指向的内存地址中取出的值,那么ESI
的值是哪来的呢?
2.5 ESI寻找
现在要寻找ESI
的值是从哪来的。因为call CElement::GetDocPtr
的位置上面很多地方都可以跳转过来,所以这里需要进行动态调试,我经过多次测试之后,跟踪了跳到这的路径,如下:
总结下来就是这样:
EAX
=[EBP-8]
=CEventObj::GetParam
函数获取的值ESI
=[EAX]
ECX
=EBX
=[ESI]
2.6 ECX的真相
通过上面的分析,终于搞清了ECX
的最终来源是[EBP-8]
。但还是很懵逼,[EBP-8]
里面到底是什么,需要知道CEventObj::GetParam
这个函数获取了什么才行。在网上搜索到的关于这个的一些说明,如下:
也就是说CEventObj::GetParam
这个函数是获取EVENTPARAM
这个结构体的指针的,那么上面的总结应该变成这样:
EAX
=[EBP-8]
=EVENTPARAM
结构体指针ESI
=[EAX]
=CTreeNode
类指针ECX
=EBX
=[ESI]
=CImgElement
类指针
用C++
表示大概是这样的:ECX = EVENTPARAM.CTreeNode.CImgElement
2.7 样本执行流程
现在知道了ECX
就是CImgElement
类指针。而程序崩溃原因是因为ECX
的值被修改成了一个错误的值,也就是说CImgElement
类指针是错误的。而CImgElement
类指针是保存在CTreeNode
类指针所指向的内存空间中,没猜错的话这个CImgElement
类指针是CTreeNode
类对象的一个成员属性。类成员属性被改了,那就得分析分析为何被改了,如下:
JavaScript
不是很好,上面的分析也是通过网上资料分析的,分析的比较乱,将就着看吧。主要的执行流程就是:
- 通过
onload事件
执行了一个函数 - 进行堆喷射
- 拷贝了一个事件对象,也就是
span
创建出的对象 - 将
span
创建出的对象给释放了 - 设置了一个定时器,去执行了拷贝对象的
srcElement
函数
最重要的两个函数详细分析如下:
|
|
2.8 验证猜想
上面的函数分析,我是根据网上的资料分析,并进行实验后写的。CTreeNode
类指针所指向的内存空间被修改的原因是因为这个类被释放了,然后就被其他变量所覆盖了。这里验证一下,观察CTreeNode
类指针修改的原因是否真的是因为类被释放了:
首先修改样本代码:
然后在执行
CElement::GetDocPtr
的位置下断点,当断在此的时候ESI
就是CTreeNode
类指针:然后访问修改前后的样本网页,对比观察
ESI
指向的内存空间:修改前:
修改后:
通过上面的测试,可以很明显的看出CTreeNode
类指针的确是在被释放之后才被修改的,也就验证了上面的分析。
2.9 漏洞成因
验证了CTreeNode
类指针修改的原因之后,漏洞成因也就很清楚了。通俗一点就是new
了一个对象,然后将指针复制了一份,接着释放了对象,然后使用复制的指针去获取了内容并执行,用C++
代码表示就是这样:
|
|
2.10 引发漏洞的语句
引发漏洞最主要的三条语句:
3. 漏洞利用
既然都知道漏洞成因了,就可以进行漏洞利用了。这里只针对IE6.0
利用一下,其他的版本又要去考虑绕过保护机制的一些东西了。
- 首先将堆喷射的代码改一改:
|
|
接着在调用
CElement::GetDocPtr
的位置下条件断点
:ECX==0x0C0D0C0D
接着重新运行IE,然后访问修改后的样本文件,断下来时
ECX
已经为0x0C0D0C0D
:跟到
CElement::GetDocPtr
去执行,可看到EAX
被赋值为0x0D0C0D0C
,而执行的位置为0x0C0D0C0D
:然后跟进去执行,
Ctrl+B
搜索90909090
,然后下断,运行,可以看到程序顺利的执行到填充的90909090
的位置:
4. END
这次漏洞分析就到这里结束了,从最开始的流量分析、提取出样本,再到后面的漏洞成因分析,最后到漏洞的利用,这一套流程算是完整的走了一遍,收获蛮大的。真的感觉发现这个漏洞的大佬是真的吊,就是不知道通过啥方式找到的这种漏洞,这是一个坎啊。这次还是很感谢搞出这个流量题的 @老刘,还有帮助了我很多的 @梦轩老哥。
由于这是我第一次接触UAF
漏洞,以及第一次从漏洞的一无所知到最终完成分析的过程,其中难免会有分析错误的地方。如果大佬们发现有什么不对的地方,望斧正!
- 样本代码中有两处类似于堆喷的地方,为啥会有多个?
- 事件对象详细的执行流程
- 如何修复与防范