_ _
(_) | |
__ ____ __ _ _ _ _ __ ___ _ __ _ __ ___ | |_
\ \ / /\ \/ /| || | | || '_ ` _ \ | '_ \ | '_ \ / _ \| __|
\ V / > < | || |_| || | | | | || |_) |_ | | | || __/| |_
\_/ /_/\_\| | \__,_||_| |_| |_|| .__/(_)|_| |_| \___| \__|
_/ | | |
|__/ |_|
/---------------------------------------------------------------------------------------\
|>...................[ 漏洞CVE-2012-1889逆向分析 ]...................<|
|>......................[ by nEINEI/vxjump.net ]......................<|
|>......................[ 2012-07-20 ]......................<|
\>...................... [ neineit_at_gmail.com ] ......................
[目录]
[0x01] .简介
[0x02] .基本信息
[0x03] .漏洞分析
[0x04] .其它
[0x01] .简介
漏洞CVE-2012-1889是由Google Security Team和360安全团队同时发现的0day漏洞,更新在微软的安全公告MS-12-043.
https://technet.microsoft.com/library/security/ms12-043
这是一个在IE浏览器中,因为未初始化栈空间数据而引发的漏洞。
[0x02] .基本信息
这个漏洞发生的模块是在Msxml3.dll(Microsoft Xml Core Services 3.0 ~ 6.0),影响包括:WINXP ~ WIN7x64 ,IE6~1E9或offie系列.
这里我们以Windows7 为例讨论这个问题,其它平台类似。
我调试时触发漏洞的一个版本:
72800000 72933000 msxml3 (pdb symbols) c:\symbols\msxml3.pdb\A7061EAE9A4C48CEB585A18A483419392\msxml3.pdb
Loaded symbol image file: C:\Windows\System32\msxml3.dll
Image path: C:\Windows\System32\msxml3.dll
Image name: msxml3.dll
Timestamp: Sat Nov 20 04:02:49 2010 (4CE7B8E9)
CheckSum: 0013B6DD
ImageSize: 00133000
File version: 8.110.7601.17514
Product version: 8.110.7601.17514
File flags: 0 (Mask 3F)
File OS: 40004 NT Win32
File type: 2.0 Dll
File date: 00000000.00000000
Translations: 0000.04b0
CompanyName: Microsoft Corporation
ProductName: Microsoft(R) MSXML 3.0 SP11
InternalName: MSXML3.dll
OriginalFilename: MSXML3.dll
ProductVersion: 8.110.7601.17514
FileVersion: 8.110.7601.17514
FileDescription: MSXML 3.0 SP11
LegalCopyright: Copyright (C) Microsoft Corporation. 1981-2008
漏洞利用的最后一个版本:8.0.7601.17514
补丁后的版本: 8.110.7601.17857
[0x03] .漏洞分析
先看一个PoC,运行这个页面代码将Crash,
Ms XML core service vulnerability CVE-2012-1889.
程序会崩溃在msxml3.dll模块当中,
(12c.604): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=72840ab6 ebx=00000000 ecx=fc774ae9 edx=00000001 esi=72840ab6 edi=0832d460
eip=7284e2ee esp=0832d0e4 ebp=0832d220 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
msxml3!_dispatchImpl::InvokeHelper+0xb3:
7284e2ee ff5118 call dword ptr [ecx+18h] ds:0023:fc774b01=????????
ecx是一个高端地址,显然在32位下这个内核地址空间,用户态不可能出现这样的值,所以我们需要追查一下ecx是由
什么数据影响的。
先简单看一下堆栈情况: 包含msxml3模块几个函数,但看起来似乎供漏洞追踪的参考意义不大。
0:015> kp
ChildEBP RetAddr
0876d238 7283120c msxml3!_dispatchImpl::InvokeHelper+0xb3
0876d274 72831d16 msxml3!_dispatchImpl::Invoke+0x9b
0876d2b4 72831caf msxml3!DOMNode::Invoke+0xa4
0876d2e8 728321db msxml3!DOMDocumentWrapper::Invoke+0x5d
0876d344 7283215d msxml3!_dispatchImpl::InvokeEx+0x10f
0876d374 7034a26e msxml3!_dispatchEx::InvokeEx+0x2d
0876d3b0 7034a1b9 jscript!IDispatchExInvokeEx2+0x104
0876d3ec 7034a43a jscript!IDispatchExInvokeEx+0x6a
0876d4ac 7034a4e4 jscript!InvokeDispatchEx+0x98
0876d4e0 7035d9a8 jscript!VAR::InvokeByName+0x139
0876d52c 7035da4f jscript!VAR::InvokeDispName+0x7d
0876d558 7035e4c7 jscript!VAR::InvokeByDispID+0xce
0876d6f4 70355d7d jscript!CScriptRuntime::Run+0x2b80
0876d7dc 70355cdb jscript!ScrFncObj::CallWithFrameOnStack+0xce
0876d824 70355ef1 jscript!ScrFncObj::Call+0x8d
0876d8a0 7035620a jscript!CSession::Execute+0x15f
...
从崩溃的代码向上查看,可以看到
msxml3!_dispatchImpl::InvokeHelper:
...
.text:7284E2D9 mov ecx, [eax] // 是由这里的eax污染的
.text:7284E2DB push [ebp+arg_1C]
.text:7284E2DE push [ebp+arg_18]
.text:7284E2E1 push edi
.text:7284E2E2 push 3
.text:7284E2E4 push [ebp+arg_C]
.text:7284E2E7 push offset _GUID_NULL
.text:7284E2EC push ebx
.text:7284E2ED push eax
.text:7284E2EE call dword ptr [ecx+18h] // 这里崩溃
继续查看eax的受控制值,
msxml3!_dispatchImpl::InvokeHelper:
...
.text:7284E2AA lea eax, [ebp+var_1C] // (1)eax赋值
.text:7284E2AD push eax ; pvarg
.text:7284E2AE call ds:__imp__VariantInit@4 ; VariantInit(x)
.text:7284E2B4 push ebx
.text:7284E2B5 lea eax, [ebp+var_1C] // (1)eax赋值
.text:7284E2B8 push eax
.text:7284E2B9 push 2
.text:7284E2BB push ebx
.text:7284E2BC push [ebp+arg_8]
.text:7284E2BF push [ebp+arg_0]
.text:7284E2C2 call dword ptr [esi+20h] // (2)这里调用了msxml3!DOMNode::get_definition
.text:7284E2C5 cmp eax, ebx
.text:7284E2C7 jl loc_72831C30
.text:7284E2CD mov eax, dword ptr [ebp+var_1C.anonymous_0+8] //(3)这里是最后赋值给eax的值
.text:7284E2D0 mov esi, eax
.text:7284E2D2 cmp eax, ebx
.text:7284E2D4 jz short loc_7284E2FF
.text:7284E2D6 push [ebp+arg_20]
.text:7284E2D9 mov ecx, [eax] // 是由这里的eax污染的
目前,我们已经可以看出漏洞可能的原因 ebp+var_1c 是一个临时变量,而这个变量并没有被完全的初始化导致,后续直接对该变量指向内存
中的内存进行了引用,最终导致crash.
(1)(2)(3)上面我已经标识出和漏洞触发有关的关键点,显然(3)是最后污染的,那么(2)中是由对eax赋值数据的操作的,我们确认是(2)中没有对他进行
调用后的初始化工作。
漏洞引发语句是 document.getElementById("exp").object.definition(1234567);
查看相关的定义
0:000> x msxml3!*definition*
72890b93 msxml3!SymbolManager::endDefinition =
72878881 msxml3!W3CDOMWrapper::get_definition =
72871861 msxml3!DOMNode::get_definition =
72877217 msxml3!DOMDocumentWrapper::get_definition =
728777f4 msxml3!W3CDOMWrapper::get_definition =
72890ad2 msxml3!Symbol::beginDefinition =
72891535 msxml3!SymbolManager::beginDefinition =
72890d3c msxml3!VariableSymbol::endDefinition =
7287747a msxml3!DOMDocumentWrapper::get_definition =
728785ed msxml3!W3CDOMWrapper::get_definition =
728b96c0 msxml3!CXTLRuntimeObject::get_definition =
72891261 msxml3!AttrSetSymbol::endDefinition =
728708db msxml3!Node::getDefinition =
728912f5 msxml3!Symbol::endDefinition =
72878dc7 msxml3!W3CDOMWrapper::get_definition =
通过crash位置及对着信息判断,触发问题的地方是,
msxml3!DOMNode::get_definition =
下断点:
bu msxml3!DOMNode::get_definition
单步跟踪知道漏洞崩溃,在这里一路我们发现,eax是由下面这条语句赋值的
eax=00000001 ebx=00000000 ecx=72871922 edx=00000001 esi=728c8b60 edi=0876d460
eip=7284e2cd esp=0876d108 ebp=0876d220 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
msxml3!_dispatchImpl::InvokeHelper+0x92:
7284e2cd 8b45ec mov eax,dword ptr [ebp-14h] ss:0023:0876d20c=72840ab6
eax指向的值是:fc774ae9 ,就是崩溃时的ecx内容。
0:014> dd 72840ab6
72840ab6 fc774ae9 0c75ffff 9090f0eb 8b909090
72840ac6 ec8b55ff 8b1075ff 75ff0845 1cc0830c
72840ad6 a045e850 c25dfffd 458b000c 0000c60c
72840ae6 fd4e1ae9 909090ff ff8b9090 56ec8b55
显然,ebp=0876d220, ebp-14 = 0876d20c . 下面这条语句使用的ebp-1c。
.text:7284E2AA lea eax, [ebp+var_1C] // (1)eax赋值
至此,我们已经知道,ebp-0x1c 就是一个临时变量,显示调用VariantInit进行了简单初始化,然后调用(2)msxml3!DOMNode::get_definition
也应该初始化调用这片内存,但实际上没有这样做。导致后续产生的问题。
仔细排查msxml3!DOMNode::get_definition这个函数,可以看到这样本赋值语句,但只是初始化了ebp-1c,而不是ebp-14.
msxml3!DOMNode::get_definition+0xb9:
7287191a 8b45e4 mov eax,dword ptr [ebp-1Ch] ss:0023:0876d0a4=00000001
F5后,
signed int __stdcall DOMNode::get_definition(DOMNode *this, struct IXMLDOMNode **a2)
{
struct TLSDATA *v2; // eax@1
struct TLSDATA *v3; // ebx@1
signed int result; // eax@2
Node *v5; // eax@5
char v6; // [sp+10h] [bp-34h]@3
struct TLSDATA *v7; // [sp+24h] [bp-20h]@1
int v8; // [sp+28h] [bp-1Ch]@3
CPPEH_RECORD ms_exc; // [sp+2Ch] [bp-18h]@5
v2 = g_pfnEntry();
v3 = v2;
v7 = v2;
if ( v2 )
{
OMReadLock::OMReadLock((DocumentLock *)&v6, v2, (int)this);
v8 = 0;
if ( a2 )
{
ms_exc.registration.TryLevel = 0;
v5 = Node::getDefinition(*((Node **)this + 7));
if ( v5 )
*a2 = (struct IXMLDOMNode *)Node::getDOMNodeWrapper(v5);
else
v8 = 1; //只清空了这里,int v8; // [sp+28h] [bp-1Ch]@3 ,应该清空更大的内存空间
ms_exc.registration.TryLevel = -2;
OMReadLock::~OMReadLock((OMReadLock *)&v6);
g_pfnExit(v7);
result = v8;
}
else
{
OMReadLock::~OMReadLock((OMReadLock *)&v6);
g_pfnExit(v3);
result = 0x80070057;
}
}
else
{
g_pfnExit(0);
result = -2147467259;
}
return result;
}
所以,漏洞出问题的地方应该是DOMNode::get_definition函数,在进入出错分支后,应该清空栈中参数。而在msxml3!_dispatchImpl::InvokeHelper
当中也应该对其传入产生进行判断。
对比其补丁验证我们的判断:
eax=00000000 ebx=00000000 ecx=058147d8 edx=00000000 esi=0581479c edi=01f8d114
eip=6f9a1903 esp=01f8cf84 ebp=01f8cfc8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
msxml3!DOMNode::get_definition+0x72:
6f9a1903 891f mov dword ptr [edi],ebx ds:0023:01f8d114=6f970ab6
0:005> dd 6f970ab6
0:005> dd 01f8d114 (清空为0了)
01f8d114 00000000 01f995d8 00000006 00000000
01f8d124 01f995d8 01f8d164 6f96120c 0581479c
01f8d134 00000000 00000017 00000001 00000001
01f8d144 01f8d368 00000000 01f8d378 01f8d244
相当于:
signed int __stdcall DOMNode::get_definition(DOMNode *this, struct IXMLDOMNode **a2)
{
...
OMReadLock::OMReadLock((DocumentLock *)&v6, v2, (int)this);
if ( a2 )
{
ms_exc.registration.TryLevel = 0;
v5 = Node::getDefinition(*((Node **)this + 7));
if ( v5 )
{
*a2 = (struct IXMLDOMNode *)Node::getDOMNodeWrapper(v5);
}
else
{
*a2 = 0; //清空**********************************00000000000000*************
v3 = 1;
v7 = 1; //临时变量都初始化数据值了
}
...
}
[0x04] .其它
CVE-2012-1889作为一个栈溢出漏洞在当前的日子里面已经算是不多的情况了,通过脚本层面上对栈中数据进行布局使得未初始化数据刚好能够控制
ecx调用完成最后的漏洞那个利用。