实验环境
推荐使用的环境 | 备注 | |
---|---|---|
操作系统 | Windows 7 SP1 | |
虚拟机 | Vmware | |
调试器 | Windbg | |
反汇编器 | IDA Pro | |
漏洞软件 | IE |
动态分析
打开ie,拖进poc,windbg附加最下面的ie进程,点击
允许。
kv栈回溯
断的地方和书上大差不差。可以看出也是虚函数调用的地方,不过我的对象指针直接不可访问了。(后来才发现原来我默认加上了hpa)
从上面输出的堆信息可以断定此处是引用已释放的堆地址导致的崩溃,从栈回溯来看这里引用的是被删除的CGenericElement对象。
静态分析
poc中第一句js语句创建了span元素。
在windbg中使用x命令查找符号。
CDocument::createElement调用的CDocument::createElementHelper
CDocument::createElementHelper调用CMarkup::CreateElement
CMarkup::CreateElement最后调用CreateElement
g_atagdesc是CreateElement函数的列表。
既然创建的span元素肯定使用的是如下函数
这里调用CElement::CElement将元素内容写入分配内存。eax esi在进入该函数前均为分配内存地址。
bu mshtml!CElement::CElement+0x1e ".echo '===CElement===';dd edi l(28/4);gc"
这是查看Element元素内存
bu mshtml!CreateElement+0x41 "ln eax;gc"
打印Element地址
bu 6637d6de+37 "ln eax;gc"
打印调用的构造函数
结果如下:
'===CElement==='
09554fd8 66205570 00000001 00000008 00000000
09554fe8 00000000 00000000 00000000 00000000
09554ff8 00000000 00000000
(663477d2) mshtml!CCommentElement::CreateElement | (66347880) mshtml!`string'
Exact matches:
mshtml!CCommentElement::CreateElement = <no type information>
'===CElement==='
07c71fc8 66205570 00000001 00000008 00000000
07c71fd8 00000000 00000000 00000000 00000000
07c71fe8 00000000 00000000
(663477d2) mshtml!CCommentElement::CreateElement | (66347880) mshtml!`string'
Exact matches:
mshtml!CCommentElement::CreateElement = <no type information>
'===CElement==='
07986fc8 66205570 00000001 00000008 00000000
07986fd8 00000000 00000000 00000000 00000000
07986fe8 00000000 00000000
(66341547) mshtml!CHtmlElement::CreateElement | (66341598) mshtml!CHtmlElement::`vftable'
Exact matches:
mshtml!CHtmlElement::CreateElement = <no type information>
'===CElement==='
09496fd8 66205570 00000001 00000008 00000000
09496fe8 00000000 00000000 00000000 00000000
09496ff8 00000000 00000000
(6634181d) mshtml!CHeadElement::CreateElement | (66341868) mshtml!CHeadElement::`vftable'
Exact matches:
mshtml!CHeadElement::CreateElement = <no type information>
'===CElement==='
05ddafd8 66205570 00000001 00000008 00000000
05ddafe8 00000000 00000000 00000000 00000000
05ddaff8 00000000 00000000
'===CElement==='
09486fd0 66205570 00000001 00000008 00000000
09486fe0 00000000 00000000 00000000 00000000
09486ff0 00000000 00000000
(66340bba) mshtml!CBodyElement::CreateElement | (66340c08) mshtml!CBodyElement::CBodyElement
Exact matches:
mshtml!CBodyElement::CreateElement = <no type information>
'===CElement==='
04375fd0 66205570 00000001 00000008 00000000
04375fe0 00000000 00000000 00000000 00000000
04375ff0 00000000 00000000
'===CElement==='
09412fd0 66205570 00000001 00000008 00000000
09412fe0 00000000 00000000 00000000 00000000
09412ff0 00000000 00000000
(663477d2) mshtml!CCommentElement::CreateElement | (66347880) mshtml!`string'
Exact matches:
mshtml!CCommentElement::CreateElement = <no type information>
'===CElement==='
08ec3fc8 66205570 00000001 00000008 00000000
08ec3fd8 00000000 00000000 00000000 00000000
08ec3fe8 00000000 00000000
(6639f96d) mshtml!CScriptElement::CreateElement | (6639f9b7) mshtml!CScriptElement::CScriptElement
Exact matches:
mshtml!CScriptElement::CreateElement = <no type information>
'===CElement==='
08ebff98 66205570 00000001 00000008 00000000
08ebffa8 00000000 00000000 00000000 00000000
08ebffb8 00000000 00000000
(662f8f8c) mshtml!CSpanElement::CreateElement | (662f8fd8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'===CElement==='
08e56fd8 66205570 00000001 00000008 00000000
08e56fe8 00000000 00000000 00000000 00000000
08e56ff8 00000000 00000000
(662f8f8c) mshtml!CSpanElement::CreateElement | (662f8fd8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'===CElement==='
091e4fd8 66205570 00000001 00000008 00000000
091e4fe8 00000000 00000000 00000000 00000000
091e4ff8 00000000 00000000
(662f8f8c) mshtml!CSpanElement::CreateElement | (662f8fd8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'===CElement==='
08605fd8 66205570 00000001 00000008 00000000
08605fe8 00000000 00000000 00000000 00000000
08605ff8 00000000 00000000
(6630c4de) mshtml!CGenericElement::CreateElement | (6630c523) mshtml!CGenericElement::CGenericElement
Exact matches:
mshtml!CGenericElement::CreateElement = <no type information>
'===CElement==='
07d46fc8 66205570 00000001 00000008 00000000
07d46fd8 00000000 00000000 00000000 00000000
07d46fe8 00000000 00000000
(662ea55d) mshtml!CTable::CreateElement | (662ea59e) mshtml!CTable::CTable
Exact matches:
mshtml!CTable::CreateElement = <no type information>
'===CElement==='
07980fb8 66205570 00000001 00000008 00000000
07980fc8 00000000 00000000 00000000 00000000
07980fd8 00000000 00000000
(662dd66d) mshtml!CHRElement::CreateElement | (662dd6c3) mshtml!CHRElement::ApplyDefaultFormat
Exact matches:
mshtml!CHRElement::CreateElement = <no type information>
'===CElement==='
03adefd8 66205570 00000001 00000008 00000000
03adefe8 00000000 00000000 00000000 00000000
03adeff8 00000000 00000000
mshtml!CCommentElement::CreateElement 可能是<!doctype html>
然后html,head,body,Comment可能是<ttttt:whatever id="myanim"/>,然后script,三个span,CGenericElement,CTable,CHRElement
查看完元素构造过程,下面看append函数。document.body.appendChild(f0);
CElement::appendChild调用CElement::insertBefore
CElement::insertBefore调用CElement::InsertBeforeHelper
该函数会找到插入位置然后插入。
此处是在body插入span f0,
找到插入位置后执行插入操作
这里缺少符号表啊,书上是
我的是
可能mshtml版本不同?
发现我的mshtml和作者的不一样(明明ie版本一样),跟不了了,看书。
在获取了Doc后会调用CDoc::InsertElement函数,其尾部调用CMarkup::InsertElementInternal函数。
突然发现虽然我多走了几步还是能跟回来,
bu CMarkup::InsertElementInternal+1ec ".echo '===CTreeNode===';dd eax l1;dps poi(eax) l1;gc"
该断点打印 CTreeNode::CTreeNode的返回值。
最后看一下append时候的断点打印结果:
#### 创建f0 ####
(662f8f8c) mshtml!CSpanElement::CreateElement | (662f8fd8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'===CElement==='
08204fd8 66205570 00000001 00000008 00000000
08204fe8 00000000 00000000 00000000 00000000
08204ff8 00000000 00000000
'===CTreeNode==='
094b4fb0 08204fd8
08204fd8 662f8fd8 mshtml!CSpanElement::`vftable'
#### 创建f1 ####
(662f8f8c) mshtml!CSpanElement::CreateElement | (662f8fd8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'===CElement==='
07e6cfd8 66205570 00000001 00000008 00000000
07e6cfe8 00000000 00000000 00000000 00000000
07e6cff8 00000000 00000000
'===CTreeNode==='
08e56fb0 07e6cfd8
07e6cfd8 662f8fd8 mshtml!CSpanElement::`vftable'
#### 创建f2 ####
(662f8f8c) mshtml!CSpanElement::CreateElement | (662f8fd8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'===CElement==='
07eb1fd8 66205570 00000001 00000008 00000000
07eb1fe8 00000000 00000000 00000000 00000000
07eb1ff8 00000000 00000000
'===CTreeNode==='
093f8fb0 07eb1fd8
07eb1fd8 662f8fd8 mshtml!CSpanElement::`vftable'
#### f2中添加datalist ####
(6630c4de) mshtml!CGenericElement::CreateElement | (6630c523) mshtml!CGenericElement::CGenericElement
Exact matches:
mshtml!CGenericElement::CreateElement = <no type information>
'===CElement==='
08e68fc8 66205570 00000001 00000008 00000000
08e68fd8 00000000 00000000 00000000 00000000
08e68fe8 00000000 00000000
'===CTreeNode==='
079d6fb0 08e68fc8
08e68fc8 6630c590 mshtml!CGenericElement::`vftable'
#### f1中添加table ####
(662ea55d) mshtml!CTable::CreateElement | (662ea59e) mshtml!CTable::CTable
Exact matches:
mshtml!CTable::CreateElement = <no type information>
'===CElement==='
03cc4fb8 66205570 00000001 00000008 00000000
03cc4fc8 00000000 00000000 00000000 00000000
03cc4fd8 00000000 00000000
'===CTreeNode==='
0895cfb0 03cc4fb8
03cc4fb8 66206488 mshtml!CTable::`vftable'
#### f1中添加hr ####
(662dd66d) mshtml!CHRElement::CreateElement | (662dd6c3) mshtml!CHRElement::ApplyDefaultFormat
Exact matches:
mshtml!CHRElement::CreateElement = <no type information>
'===CElement==='
09402fd8 66205570 00000001 00000008 00000000
09402fe8 00000000 00000000 00000000 00000000
09402ff8 00000000 00000000
'===CTreeNode==='
0947cfb0 09402fd8
09402fd8 66209250 mshtml!CHRElement::`vftable'
回顾我们最开始的错误信息,CGenericElement是在h2添加datalist的时候创建的。
然后f0.offsetParent=null; //required
将f0的祖先置空(解除关系)。
查看可能的函数
最后CElement::get_offsetParent调用的还是CElement::GetOffsetParentHelper
在CElement::GetOffsetParentHelper打断点观察f0节点treenode的数据变化。
CTreeNode+8和CTreeNode+C的数据可以,在上面下写断点。
后续可以观察一下变化,但是首先看一下Treenode的定义更好点。CTreeNode+4是父节点的CtreeNode结构,CTreeNode+8是一些标记位定义,CTreeNode+C是定义CharFormat的整数值_iCF,f0.offsetParent=null会将其置1,这样它就不会调用CTreeNode::GetCharFormatHelper重新计算格式用作后续渲染,导致原本未被渲染的节点被误以为渲染了。
然后继续执行js,执行前后节点.innerhtml变化如下:
最后执行CollectGarbage函数进行垃圾回收,从前面可以知道CGenericElement就是在垃圾回收时被释放的。从图上图可以看出f1和f2的内部html代码已被情况,其所占内存就会在垃圾回收时被释放,此时的CGernericElement对象,也就是f2中的datalist元素已被情况,所以CGernericElement内存被一并释放,f1中的Table元素也被释放。
这里补充一点结构信息。
CTextBlock结构
+00 vftable
+04 count
+0c startPos
+10 endPos
+1c Prev
+20 Next
+58 element_array
后续打条件断点继续追踪CTextBlock中的element_array变化。
发现在垃圾回收之后,虽然f0和f1的innerHTML被清空,但是f2的CTextBlock里面的element_array依然是span嵌套着datalist元素。也就是说DOM树结构改变,但内存中与DOM数相关的结构CTextBlock没更新。
接下载f0中添加hr子元素,会改变DOM结构,此时会重新遍历DOM树,其中就包括了已经被释放的CGernericElement对象。
执行完js后重新渲染页面,计算节点格式,这里就会引用到指向已释放对象的CGenericElement的CTreeNode结构。
漏洞利用
漏洞利用无非还是申请到CGenericElement然后修改虚表地址和对应偏移处虚函数指针。这里的是70h。
总结
写这个的时候实在太困了,建议随便看看得了,需要更多信息可以参考https://www.cnblogs.com/binarysystemloophole/articles/11062794.html的分析。
感觉复杂调试的时候对一些数据结构的收集整理,关键变量的打印挺重要的,函数猜测定位也挺重要的。
- 代码中对f0.offsetParent进行置空,会设置ICF格式整数值为1,使得他不做节点格式计算,相当于被标记为已渲染状态,由于设置f0的父节点bodu,会导致其相邻的f1和f2都受到影响,各个CTreeNode中的iCF都被置1,使得原本没有被渲染误以为被渲染了。
- 在f0添加hr子元素,会改变DOM树结构进行重绘,此时就需要遍历CTreeNode,就会引用到CGnericElement的CTreeNode结构。
- 垃圾回收后,由于第一步的原因,导致CGnericElement的CTreeNode结构未被删除,虽然DOM树的结构以变,但由于构建页面布局的CTexBlock也依然保存这对CGnericElement的引用,而此时CGnericElement早因为f2.innerHTML被清空而释放掉,最终导致uaf漏洞的产生。
- 从上面这些信息,其中导致漏洞的原因跟f0、f1、f2元素关系不大,但必须是块元素和内联元素(否则不会进入CLayoutBlock::BuildBlock构建CTextBlock),比如其中的span、datalist可以替换成u下划线和a标签,此时崩溃对象就不是CGnericElement,而可能是CAnchorElement或者CSpanElement对象,关键在于你poc中所设置的具体元素,而块元素table,也是可以用p或div这样的块元素代替,但是hr不可替换,只有他才会去遍历寻找CTreeNode,进入漏洞触发流程。
- ust:用来追踪堆的分配过程。很多时候我们找到了一块堆内存,却不知道这个堆内存是谁分配的。ust就是用来解决这个问题的,ust有自己的一块内存区作为数据库。每次堆分配函数被调用时,分配函数的栈回溯都会被保存进数据库,这样,想知道堆是谁分配的就可以看栈回溯了。
问题
bu 函数名+偏移最后打断点会很奇怪,不知道是符号表和dll没对应还是啥关系。
文章评论