CVE-2010-3962分析
 
相关代码参考win2k:win2k\private\inet\mshtml\src\site\download\
 
问题代码为:

代码:
<table style=position:absolute;clip:rect(0)>
 
 
分析步骤:
 
引用:
1. html解析器(CHtmParse::ParseEof)在解析到html尾部(最后一个括号)时发现当前结点(table结点)还需要一个隐式的_etagTextSubcontainer对象,这里由TableHtmParseClass决定_etagTextSubcontainer到底是什么,具体见下。
 
 
// TABLE

static CHtmlParseClass s_hpcTable =
{
    SCOPE_NESTED,                   // _scope
    TEXTTYPE_ALWAYS,                // _texttype                    ; textlike; force BODY etc
    s_atagTable,                    // _atagEndContainers
    s_atagTableCellCaption,         // _atagBeginContainers         ; allow nesting inside TD, CAPTION, TABLE
    NULL,                           // _atagMaskingContainers
    s_atagTableCloses,              // _atagProhibitedContainers    ; close prevous TABLE, TC, SELECT, OPTION
    NULL,                           // _atagRequiredContainers
    ETAG_NULL,                      // _etagDefaultContainer
    FALSE,                          // _fQueueForRequired
    TEXTSCOPE_EXCLUDE,              // _textscope                   ; exclude text
    ETAG_TC,                        // _etagTextSubcontainer        ; wrap contained text in a TC
    NULL,                           // _atagMatch
    ETAG_NULL,                      // _etagUnmatchedSubstitute
    NULL,                           // _pfnHpxCreator
    FALSE,                          // _fMerge
    ETAG_NULL,                      // _etagImplicitChild
    FALSE,                          // _fCloseImplicitChild
};
 
引用:
2. 所需etagTextSubcontainer对象名为CTableCaption、类型为ETAG_TC(标题类型)、值为0x62,随后CTableCaption对象被创建之.
引用:
3. CTableLayout管理器会负责管理要显示的table,并把上面创建的CTableCaption对象加到标题数组中去。

引用:
4. html解析器随后会通知各HTML元素刷新,table标签中的CTableCaption对象也会刷新显示。
引用:
5. CTableLayout检查到要显示的结点中含有标题对象时,会检查该标题对象是否有显示结点容器CDispContainer,当不存在时需为该标题对象创建CDispContainer类型的显示容器对象,同时由于table标签具有style=position:absolute;clip:rect(0)因而需要对显示的结点进行裁剪,这些信息也会保存到CDispContainer对象中,以供显示之用,不巧的是CDispContainer是一个变体大小的对象,最小有0x48字节,附加大小是由一张静态表控制:Sizeof(CDispContainer) = _extraSizeTable[index]*4+0x48_extraSizeTable[index]*4大小的数据用来存放裁剪信息CDispContainer的基本结构为
---------------------------------------------------
CliprectInfo|VT|CliprectInfo_size|................
---------------------------------------------------
引用:
6. 带标题属性而没有CDispContainer结点的结果导致动态生成index的值为0,这样新生成的对象会只有0x48大小而CliprectInfo为空,那么在设置CliprectInfo时导致VT表直接被修改.

 
代码:
.text:7E2C5D9D                                         ; 
.text:7E2C5D9D                 push    eax
.text:7E2C5D9E                 lea     eax, [ebx+0Ch]
.text:7E2C5DA1                 push    eax
.text:7E2C5DA2                 call    CDispContainer::New(CDispClient *,ulong)

*******************************************************
代码:
.text:7E2B5D2A CDispContainer::New
..........................................................
.text:7E291CF0    movzx   esi, ds:uchar const * const CDispNode::_extraSizeTable[ebx]
.text:7E291CF7                 shl     esi, 2
.text:7E291CFA                 push    edi
.text:7E291CFB                 add     eax, esi
.text:7E291CFD                 push    eax             ; dwBytes
.text:7E291CFE                 call    _MemAllocClear(x)
.text:7E291D03                 mov     edi, eax
.text:7E291D05                 test    edi, edi
.text:7E291D07                 jz      short loc_7E291D17
.text:7E291D09                 add     edi, esi
.text:7E291D0B                 test    bl, 40h
.text:7E291D0E            mov     [edi+4], ebx <-------这里保存CliprectInfo_size的大小

*******************************************************
代码:
.text:7E36B4C4 CDispNode::SetUserClip
...............................
.text:7E36B54D                 mov     eax, [edi+4] <-------当这里为0时,虚函数表就被悲剧了.
.text:7E36B550                 and     eax, esi
.text:7E36B552       movzx   ecx, ds:uchar const * const CDispNode::_extraSizeTable[eax]
.text:7E36B559                 mov     eax, edi
.text:7E36B55B                 shl     ecx, 2
.text:7E36B55E                 sub     eax, ecx
.text:7E36B560                 or      dword ptr [eax], 1   <-----------------------虚函数表被改了

<table style=position:absolute;clip:rect(0)>改为
<table style=position:absolute;clip:rect(0)><td>后将导致CTableCaption对象不会生成,因为tdCHtmlParseClass 根本没有_etagTextSubcontainer,这样不会导致代码出问题,到底是s_hpcTable出了问题还是SetUserClip检查不严格?还是两者都有问题?
 
 
函数调用序列:
代码:
 
CHtmParse::ParseEof
 
代码:
CHtmParse::ParseText
|
       CHtmlParseClass *phpc;
 
       phpc = HpcFromEtag(etag);
       if (phpc->_atagProhibitedContainers)
       {
           hr=THR(CloseAllContainers(phpc->_atagProhibitedContainers, phpc->_atagBeginContainers));
           if (hr)
               goto Cleanup;
       }
 
       hr = THR(OpenContainer(etag));

 
代码:
CHtmParse::OpenContainer
|
 
此时etagItem=0x62表示ETAG_TC,这时将创建一个CTableCaption对象
hr = THR(CreateElement(etagItem, &pel, _pDoc, _pMarkup, TRUE, &_fDie));
CreateElement函数根据etagItem=0x62去索引hash表g_atagdesc,查表具体的对象的CreateElement函数接着CTableCaption::CreateElement函数将被调用
 

 
代码:
 
CHtmPos::Exec
CHtmPos::Notify
CTableCell:Notify(CTableCaption继承该类)
 
代码:
CTableCell::EnterTree
|
 
hr = pTableLayout->AddCaption(pCaption);导致 pTableLayout对象中存在标题
 
 

 
代码:
 
CTableLayoutBlock::EnsureTableDispNode(CTableLayoutBlock即上面的pTableLayout)
 
代码:
CDispNode::SetUserClip
|
movzx   ecx, ds:uchar const * const CDispNode::_extraSizeTable[eax]
mov     eax, edi
shl     ecx, 2
sub     eax, ecx
or      dword ptr [eax], 1

 
当对CliprectInfo操作时虚函数表在这里活生生成被修改了一位,后续对对象的调用都会导致访问异常。
上传的附件 CVE-2010-3962分析.pdf