-
-
[原创]Windows 传真编辑器双重释放漏洞详细分析(CVE-2010-3974)
-
2019-4-13 23:22
9128
-
[原创]Windows 传真编辑器双重释放漏洞详细分析(CVE-2010-3974)
1.漏洞描述
Microsoft Windows传真封面主要用于个性化传真,当使用Windows传真封面编辑器打开特制的传真封面文件(.cov)时,由于它没有正确的解析cov文件,导致双重释放漏洞,最终允许任意代码执行
2.分析环境
操作系统:Windows 7
调试器:Windbg
反汇编器:IDA Pro
漏洞软件:Windows Fax Cover Page Editor
3.通过栈回溯和堆状态判定漏洞类型
打开传真封面编辑器,然后用Windbg附加进程fxscover.exe,用传真封面编辑器打开poc.cov文件,打开时会提示文件损坏,但是单击确定按钮程序就会触发异常,Windbg接收异常,在Windbg中被断下来
提示文件已损坏
如果出现提示 Symbol file could not be found,就先要下载符号,下面是下载符号链接,注意一定要勾选reload
SRV*C:\WindbgSymbol*http://msdl.microsoft.com/download/symbols
(91c.f50): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=778a07ed edx=0019edf9 esi=00230000 edi=01f3fc30
eip=7794280d esp=0019f04c ebp=0019f0c4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ntdll!RtlReportCriticalFailure+0x29:
7794280d cc int 3
触发异常被断下来
0:000> kv
ChildEBP RetAddr Args to Child 0019f0c4 7794376b c0000374 7795cdc8 0019f108 ntdll!RtlReportCriticalFailure+0x29 (FPO: [Non-Fpo])0019f0d4 7794384b 00000002 77a142c6 00230000 ntdll!RtlpReportHeapFailure+0x21 (FPO: [Non-Fpo])0019f108 77943ab4 00000003 00230000 01f3fc30 ntdll!RtlpLogHeapFailure+0xa1 (FPO: [Non-Fpo])0019f160 77907ad7 00230000 01f3fc30 00000000 ntdll!RtlpAnalyzeHeapFailure+0x25b (FPO: [Non-Fpo])0019f254 778d2d68 01f3fc30 01f3fc38 01f3fc38 ntdll!RtlpFreeHeap+0xc6 (FPO: [Non-Fpo])0019f274 773598cd 00230000 00000000 01f3fc38 ntdll!RtlFreeHeap+0x142 (FPO: [Non-Fpo])WARNING:Stack unwind information not available.Following frames may be wrong0019f2c0 0027f43a 01f3fc38 01f3fc38 0019f2ec msvcrt!free+0xcd (FPO: [Non-Fpo])0019f2d0 0027ab0c 00000001 00232f70 0023ea68 unpatch_FXSCOVER!CDrawOleObj::`vector deleting destructor'+0x1a (FPO: [Non-Fpo])0019f2ec 0027b1d4 00000000 0023ea68 72bd8515 unpatch_FXSCOVER!CDrawDoc::Remove+0x96 (FPO: [Non-Fpo])0019f2f8 72bd8515 0023ea68 72bd84df 0023ea68 unpatch_FXSCOVER!CDrawDoc::DeleteContents+0xc (FPO: [0,0,4])
程序在调用free释放内存时触发异常,当遇到这种情况,可以推测很可能是双重释放漏洞
通过栈回溯可以看到,程序依次调用了CDrawDoc::DeleteContents——CDrawDoc::Remove——CDrawOleObj::`vector deleting destructor'——free函数,也就是调用对象的构造函数时触发的,重新加载进程,并在调用free函数前更上几层的函数unpatch_FXSCOVER!CDrawDoc::DeleteContents上下断点,断下后在执行就会发生访问异常
0:000> bp
unpatch_FXSCOVER!CDrawDoc::DeleteContents
0:000> bl
0 e 00a0b1c8 0001 (0001) 0:**** unpatch_FXSCOVER!CDrawDoc::DeleteContents
0:000> g
(c48.1a4): Unknown exception - code c0000374 (first chance)
(c48.1a4): Unknown exception - code c0000374 (!!! second chance !!!)
eax=0016f3f4 ebx=00000000 ecx=778a07ed edx=0016f191 esi=001f0000 edi=01f18640
eip=7794283b esp=0016f3e4 ebp=0016f45c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!RtlReportCriticalFailure+0x57:
7794283b eb12 jmp ntdll!RtlReportCriticalFailure+0x6b (7794284f)
0:000> !address esi
Usage: Heap
Base Address: 001f0000
End Address: 00200000
Region Size: 00010000
State: 00001000 MEM_free
Protect: 00000004 PAGE_READWRITE
Type: 00020000 MEM_PRIVATE
Allocation Base: 001f0000
Allocation Protect: 00000004 PAGE_READWRITE
More info: heap owning the address: !heap 0x1f0000
More info: heap segment
More info: heap entry containing the address: !heap -x 0x1f000
断下后继续执行可以看到这里访问了已经释放的内存块,可以确认这里就是由于free函数释放内存导致的双重释放漏洞
利用该漏洞,可通过“占坑”的方式将已经释放的内存填充成自己的代码,比如程序在调用 MFC42u!Cobject::IsKindOf函数时,会引用已经释放的内存,并取出对应的内存值作为虚表指针,然后通过虚表指针索引虚函数并调用,如果能够提前在已经释放的内存块填充自己的数据作为指针索引,那么就可以控制程序的执行流程
0:000> g
Breakpoint 1 hit
eax=001fe898 ebx=001fea68 ecx=01f2c330 edx=01ef71bc esi=01f2c330 edi=001f2f70
eip=72bcb7a8 esp=0016f66c ebp=0016f684 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
MFC42u!CObject::IsKindOf:
72bcb7a8 8bff mov edi,edi
在exploit-db已经有针对此漏洞的利用代码,执行后会创建回连后门,其利用方式和UAF漏洞利用大体一致
4.通过补丁比较确定漏洞成因和修复方法
用IDA和Bindiff插件进行补丁比较,补丁比较后发现只有3个函数被修改了,从前面的分析可以看出程序是在移除CDrawDoc对象时导致双重释放的,因此这里可以重点看下CDrawDoc:Serialize函数
选中CDrawDoc:Serialize后单击鼠标右键选择“View FlowGraphs”选项,在BinDiff中打开后,发现该函数主要增加了一段代码:
用IDA打开修复后的fsxcover.exe,找到对应的代码(找的方法是:点击对比出的函数:CDrawDoc:Serialize,F5然后往下翻和未打补丁的位置对比不同),补丁代码通过遍历CPtrList链接中的文档对象指针,判断对象(主要是CDrawDoc类对象)是否已被序列化(用于加载和存储文档对象),如果未被序列化,就从链表中移除当前索引到的对象,防止后面在调用CDrawDoc:Remove移除对象时造成双重释放漏洞
由此可以知道,之前的漏洞主要是因为CPtrList链接中存在为被序列化的CDrawDoc的对象指针,而该对象指针可能指向一块已经被释放的内存,导致后面在移除CDrawDoc时造成内存的双重释放。
参考信息:泉哥《漏洞战争》
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界