• IE漏洞的调试心得


    在调试漏洞的过程中,个人感觉最棘手的就是ie浏览器的漏洞和flash player的漏洞了。这里打算记录一下学习过程中的心得(主要是基于uaf类),以方便新人学习。

    首先,ie漏洞与众不同的是,程序的执行流程是由攻击者控制的。poc中的js脚本反应到mshtml中的c++代码决定了程序的执行流程,所以对于ie漏洞来说仔细研究poc非常的关键。此外就是调试ie漏洞需要对ie本身有很强的了解,这也是我写这篇博文的动机,如果完全不清楚ie背后的机制,那么ie漏洞根本没法去调。

    调试IE漏洞的关键点:执行流程

    CMarkup代表整个HTML树结构

    CMarkup::CreateElement——>

    mshtml!CreateElement——>

    CXXXElement::CreateElement

     tips:1.析构函数在windbg里直接用符号是断不下来的,需要找到函数地址,最好是在call free上下断。

    元素对象统一继承自CElement。

    0x00偏移:虚表(dword),对此处求ln会得到符号

    0x08偏移:是引用计数?

    0x14偏移:对应的CTreeNode对象的指针

    0x24偏移:Tag (byte),0x58script 0x10body 0x2fhead

    创建函数:CXXXElement::CreateElement(通用断点:监视类型mshtml!CreateElement [call eax]、监视内存CElement::CElement [堆分配传来的eax])

    释放引用函数:CXXXElement::Release(通用断点:CBase::PrivateRelease 栈上arg_1 eax是虚表)

    释放函数:CBase::SubRelease(CElement::~CElement)(通用断点CBase::SubRelease的jmp路径 ecx为要释放的对象指针)

    DOM对象均为CTreeNode类的实例。

    0x00偏移:对应的元素对象的指针(dword)

    0x04偏移:指向父节点的CTreeNode(dword)

    0x16偏移:指向此node的起始CTreePos

    0x20偏移:指向此node的结束CTreePos

    0x40偏移:引用计数?

    创建函数:CTreeNode::CTreeNode(构造函数)(eax:缓冲区地址 edi:所属对象类型)

    释放引用函数:CTreeNode::Release的if分支(通用断点:CTreeNode::Release的if分支 [待释放的edx],在比较处eax引用计数)

    释放函数:CTreeNode::Release的另一if分支(通用断点:CTreeNode::Release的另一if分支 [待释放的edx],在比较处eax引用计数)

    CTreePos对象是一一对应于CTreeNode对象的,主要是用于构成dom树的结构

    0x00偏移:key

    0x10偏移:上一个CTreePos对象(dword)

    0x14偏移:下一个CTreePos对象(dword)

    0x18偏移:引用计数,为0就会被释放(dword)

    0x20偏移:对应的CTreeNode(dword)

    释放函数:CMarkup::FreeTreePos

    通用断点原则 

    IE中两类重要的对象:元素对象和DOM对象

    IE中每一个元素标签都对应一个c++对象,这些类的总基类是CElement

    每个元素对象都在DOM树中,但是联入数据结构的是CTreePos对象

    IE浏览器使用引用计数来跟踪对象的生命期,引用计数数=指向对象的指针,就是说每当增加一个指针指向它引用计数就加1。

    解除引用元素对象的函数都为如下,这个方法的调用执行关系如下(基于IUnknown)

      • CXXXElement::Release ——>
      • CElement::Release——>
      • CElement::PrivateRelease——>
      • CBase::PrivateRelease

    如果可以监视所有的IE元素创建、DOM元素创建、IE元素释放、DOM元素释放,那么漏洞出在哪里将一目了然

    对于一个元素标签,比如Object标签。那么对应的就是CObjectElement::CreateElement,这个函数的调用关系如下

    元素对象创建的完整路径

    • CDocument::createElement——>
    • CDocument::CreateElementHelper——>
    • CMarkup::CreateElement——>
    • mshtml!CreateElement——>
    • CXXXElement::CreateElement——>
    • HeapAlloc+CElement::CElement

    CTreeNode::SetElement(CXXXElement*);将DOM对象与元素对象关联起来

     CTreeNode表示一个节点,CTreePos表示一个节点的标记。dom树就是由CTreePos表示的二叉树。

    如果一个对象的指针计数为0,那么就会被垃圾清理释放掉

    CTreeNode类的成员,来自IE5泄露源码

        // Class Data
        CElement*   _pElement;                          // The element for this node
        CTreeNode*  _pNodeParent;                       // The parent in the CTreeNode tree
    
        // DWORD 1
        BYTE        _etag;                              // 0-7:     element tag
        BYTE        _fFirstCommonAncestorNode   : 1;    // 8:       for finding common ancestor
        BYTE        _fInMarkup                  : 1;    // 9:       this node is in a markup and shouldn't die
        BYTE        _fInMarkupDestruction       : 1;    // 10:      Used by CMarkup::DestroySplayTree
        BYTE        _fHasLookasidePtr           : 2;    // 11-12    Lookaside flags
        BYTE        _fBlockNess                 : 1;    // 13:      Cached from format -- valid if _iFF != -1
        BYTE        _fHasLayout                 : 1;    // 14:      Cached from format -- valid if _iFF != -1
        BYTE        _fUnused                    : 1;    // 15:      Unused
    
        SHORT       _iPF;                               // 16-31:   Paragraph Format
    
        // DWORD 2
        SHORT       _iCF;                               // 0-15:    Char Format
        SHORT       _iFF;                               // 16-31:   Fancy Format

    CTreeNode::CTreeNode(CTreeNode *pParent,CElement *pElement)这个构造函数的第一个参数是父CTreeNode节点,第二个参数是所属的Element对象。其中第二个参数往往为0。

    如何跟踪CTreeNode::CTreeNode对象的创建?

    断下CTreeNode::CTreeNode函数后,eax就是分配的内存地址。

    第一个参数为父节点CTreeNode对象的地址,第二个参数恒为0

    可以在call ~的下一条,mov esi,eax下断,这时CTreeNode已完成初始化,读eax就可知道是属于哪个元素

     DOM树是由CTreePos组成的一个splay tree。

    如图所示就是一个CxxxElement::CreateElement,上面已经说过了这是由mshtml!CreateElement调用的。我们可以看到调用了HeapAlloc函数后,eax的值没有改变直接传递到了CElement的构造函数——CElement::CElement中。实现了分配空间+初始化内存的操作。

    对mshtml!CElement::CElement+0x48下断可以通用的监测对象创建的内容。

    这张图是mshtml!CreateElement函数的关键部分,注意符号给出的CTagDesc *类型的常量,这是一个指针数组经过movzx eax,byte ptr [edi+1];shl eax,4;计算偏移得出CxxxElement::CreateElement的地址,然后调用过去。指针数组如下:

    CTreeNode::Release可以获取到所有的CTreeNode的释放过程,edx是上面直接传递过来的CTreeNode对象的地址。对这个值监视即可获得所有CTreeNode对象的释放

    <html>
      <head>
        <title>DOM 教程</title>
      </head>
      <body>
        <h1>DOM 第一课</h1>
        <p>Hello world!</p>
      </body>
    </html>
    mshtml!CHtmlElement::CreateElement
    mshtml!CHeadElement::CreateElement
    mshtml!CBodyElement::CreateElement
    mshtml!CHeaderElement::CreateElement
    mshtml!CParaElement::CreateElement  

    下断元素创建

    1:020> bl
     0 e 6a23480f     0001 (0001)  1:**** mshtml!CElement::CElement ".echo 对象地址;r eax;gc"
     4 e 6a234be7     0001 (0001)  1:**** mshtml!CreateElement+0x41 "ln eax;gc"
    1:020> g
    (6a23d088)   mshtml!CHtmlElement::CreateElement   |  (6a23d0d8)   mshtml!CHtmlElement::`vftable'
    Exact matches:
        mshtml!CHtmlElement::CreateElement = <no type information>
    对象地址
    eax=06131fd8
    (6a23d359)   mshtml!CHeadElement::CreateElement   |  (6a23d3a8)   mshtml!CHeadElement::`vftable'
    Exact matches:
        mshtml!CHeadElement::CreateElement = <no type information>
    对象地址
    eax=06154fd8
    对象地址
    eax=05f6afd0
    (6a2465fa)   mshtml!CBodyElement::CreateElement   |  (6a246648)   mshtml!CBodyElement::CBodyElement
    Exact matches:
        mshtml!CBodyElement::CreateElement = <no type information>
    对象地址
    eax=0302dfd0
    (6a254c88)   mshtml!CHeaderElement::CreateElement   |  (6a254ce0)   mshtml!CHeaderElement::`vftable'
    Exact matches:
        mshtml!CHeaderElement::CreateElement = <no type information>
    对象地址
    eax=0628efd0
    (6a257e72)   mshtml!CParaElement::CreateElement   |  (6a257ec0)   mshtml!CParaElement::`vftable'
    Exact matches:
        mshtml!CParaElement::CreateElement = <no type information>
    对象地址
    eax=05d83fd8

    IE漏洞调试的目的:

    crash漏洞产生原因

    找到发生UAF的对象

    找出对象的分配释放重利用的时机

    对应到poc的js语句

    推断出UAF的本质成因

    补丁对比!!!找出本质成因最好的办法

  • 相关阅读:
    linux一切皆文件之tcp socket描述符(三)
    linux一切皆文件之Unix domain socket描述符(二)
    linux一切皆文件之文件描述符(一)
    k8s之使用secret获取私有仓库镜像
    https、ssl、tls协议学习
    k8s网络之calico学习
    泛型的原理、应用、约束、缓存
    C#中Unity对象的注册方式与生命周期解析
    监听EF执行的sql语句及状态
    递归一个List<T>,可自己根据需要改造为通用型。
  • 原文地址:https://www.cnblogs.com/Ox9A82/p/5782425.html
Copyright © 2020-2023  润新知