|
作者:Peter Silberman, Steve Davis 译者:riusksk (泉哥:http://riusksk.blogbus.com)
原文出处:BlackHat USA 2009
前言
Metasploit:重现犯罪场景,旨在演示如何结合现有工具资源进行内存分析与提取,以恢复先前不易访问到的数据。此处现有的资源主要是指如何利用 payload,特别是Meterpreter,可用于检索和提取攻击者电脑中的内存。本文主要讨论如何利用Memoryze[1](一款免费使用的内存分析与提取工具)和Metasploit Forensic Framework去重现Meterpreter会话过程。在理解重现现实中的Meterpreter会话之前,读者需要先理解以下三点: 1.访问物理内存; 2.进程捕获; 3.Metasploit payload与Meterpreter。
访问物理内存
Memoryze作为内存分析工具,它访问物理内存主要出于两个目的:内存提取与内存分析。 1. 内存提取:Memoryze针对物理内存或特定进程的当前状态创建完整内存映像。 2. 内存分析:Memoryze通过访问物理内存以进行分析,比如枚举所有进程及其句柄表。 为了更为容易地访问物理内存,Windows公布一个名为\Device\PhysicalMemory的section object。这个section object一打开,应用程序即有一个指向物理内存的句柄。如果程序通过该句柄读取数据,那么它就会从物理内存中读取。重点要注意的是,在Windows 2000和Windows2003 SP0上应用程序可以在ring 3上访问section object,而在Windows 2003 SP1及之后的版本则改变了对此section object的访问权限,现在要求程序必须运行在ring 0[2]。
理解Windows进程地址空间
在访问物理内存之前,Memoryze需要访问每一进程的虚拟地址空间。地址空间大小随着如线程,动态存储,栈,被加载的可执行文件等的内存需求而进行增减。Windows Memory Manager (MM)管理着所有的这些信息,且是以二叉树的形式被管理的。在Executive Process (EPROCESS)结构当中一个名为VadRoot (Virtual Address Descriptor Root)的成员变量刚好指向该二叉树的根。每一进程均含有EPROCESS结构,其包含有进程管理器需要用来管理进程的信息。二叉树的入口实际上是一个名为Memory Manager Virtual Address Descriptors (MMVAD)结构。该结构包含有与MM相关的信息,如被描述的内存段的虚拟内存基址和大小。若想查看MMVAD结构及其成员,可在windbg中输入 dt _MMVAD的命令以显示此结构信息。通过以上命令可以显示MMVAD结构及其成员的偏移地址和大小,显示如下(确保操作前符号文件已被加载): lkd> dt _MMVAD +0x000 StartingVpn : Uint4B +0x004 EndingVpn : Uint4B +0x008 Parent : Ptr32 _MMVAD +0x00c LeftChild : Ptr32 _MMVAD +0x010 RightChild : Ptr32 _MMVAD +0x014 u : __unnamed +0x018 ControlArea : Ptr32 _CONTROL_AREA +0x01c FirstPrototypePte : Ptr32 _MMPTE +0x020 LastContiguousPte : Ptr32 _MMPTE +0x024 u2 : __unnamed
Figure 1:_ MMVAD Structure
由上可知,在Figure 1中MMVAD包含有各种成员变量。Memoryze只关心下列结构: ● StartingVpn -虚拟内存基址 ● EndingVpn -内存块的大小 ● LeftChild,RinghtChild -指向树中的子节点 ● Parent -父节点指针 如果MMVAD所描述的虚拟内存块是通过调用LoadLibrary或Windows进程加载器创建的,那么该内存块将拥有一个名称。该名称实际是存储在 MMVAD所描述的虚拟内存块上的文件名。为了获取名称或者检测文件是否存在,Memoryze引用了MMVAD中指向的CONTROL_AREA结构的 ControlArea成员变量。 lkd> dt _CONTROL_AREA +0x000 Segment : Ptr32 _SEGMENT +0x004 DereferenceList : _LIST_ENTRY +0x00c NumberOfSectionReferences : Uint4B +0x010 NumberOfPfnReferences : Uint4B +0x014 NumberOfMappedViews : Uint4B +0x018 NumberOfSubsections : Uint2B +0x01a FlushInProgressCount : Uint2B +0x01c NumberOfUserReferences : Uint4B +0x020 u : __unnamed +0x024 FilePointer : Ptr32 _FILE_OBJECT +0x028 WaitingForDeletion : Ptr32 _EVENT_COUNTER +0x02c ModifiedWriteCount : Uint2B +0x02e NumberOfSystemCacheViews : Uint2B
Figure 2: CONTROL_AREA Structure
在CONTROL_AREA结构中有一名为FilePointer的指针,其指向FILE_OBJECT结构。如果FILE_OBJECT结构有效,在成员FileName中的UNICODE_STRING buffer会指向实际的文件路径。 lkd> dt _FILE_OBJECT +0x000 Type : Int2B +0x002 Size : Int2B +0x004 DeviceObject : Ptr32 _DEVICE_OBJECT +0x008 Vpb : Ptr32 _VPB +0x00c FsContext : Ptr32 Void +0x010 FsContext2 : Ptr32 Void […] +0x030 FileName : _UNICODE_STRING […] +0x06c CompletionContext : Ptr32 _IO_COMPLETION_CONTEXT
特别要注意,一些MMVAD是没有名称的,但它的内容包含有一个MZ/PE header,可用来注入恶意代码。 通过枚举MMVAD entry处的二叉树,Memoryze可以访问进程的堆,栈,可执行文件及DLL文件。这是完全没有限制地浏览进程地址空间,且并没有“篡改”或“触碰”进程,也没有调用API函数。为了说明windows内存管理器是如何使用VAD树的,请参见Figure 3,这是OllyDbg上的内存映像截图,VAD树与此非常相似。地址栏中的每一虚拟地址在VAD tree上都有其自己的entry.
Figure 3: OllyDbg Memory Map View
进程捕获
既然读者已经理解了进程虚拟地址空间是如何设计的,那么理解进程捕获就可容易了。记住,这一切都始于内存中的进程识别。通过查找EPROCESS结构,然后检测EPROCESS结构是否与用户请求获取的进程一致。若相匹配,则VadRoot指针被引用,并遍历二叉树。每个MMVAD entry都以DD的形式,且格式未变的情况下写入到磁盘。DD是磁盘复制(disk duplicator)的意思,原本用于复制驱动器。格式很简单:从缓冲区中读取数据,然后写入到磁盘,如果缓冲区无法读取(如内存页被分页到磁盘,以及非分页文件),则缓冲区清零,相当于将试图读取的数据大小写入到磁盘,以确保了输出文件在大小上与输入文件相等。在这种情况下,输出文件将作为一个被获取的VAD和输入文件将成为内存中的虚拟内存块。如果VAD在其CONTROL_AREA结构中有名称,这将会获得该名称。否则,在其虚拟基址和大小的区域之后被命名。 Memoryze能够获得一个特定进程的地址空间,因为它有一个内置功能,可以把虚拟地址映射到物理地址。每一个虚拟地址遇到执行请求时就会被映射到其物理内存地址。然后将物理内存读入缓冲区,并写入到磁盘。如果物理内存标记为分页,则Memoryze将解析该分页文件 ,以判断该页是否映射到分页文件。如果是在分页文件中,它将被读取,然后写入到磁盘。在进程捕获过程中利用分页文件可以更好,更全面地了解进程地址空间的情况。通过物理内存进行进程捕获可以有很多好处,用户可以: ● 绕过进程中用来保护自己而使用的反调试例程。在未附加进程的情况下读取进程的虚拟内存,受保护的进程对于被“捕获”将无可奈何。 ● 绕过调试寄存器(DR)rootkit。如果你无法读取虚拟地址以检测被钩住的未知钩子,那是因为DR rootkit通过在不被读取的特定虚拟地址中设置陷阱,比如某钩子(hook)的虚拟地址。但是Memoryze只采用物理内存,因此可以完全绕过一些 DR。 ● 捕获加密前后进程中的通讯字符串。 ● 克服大部分的加壳程序,因为捕获的进程都是处于未脱壳状态。 ● 在未接触磁盘的情况下获取被注入的DLL文件。
Metasploit
Metasploit是由HD Moore在2003[3]开发的一款开源的安全漏洞检测工具, 用来进行网络安全中的漏洞发现、渗透攻击,IDS的识别标签等开发方面的开发工作。该工具在用户群和开发者中已以成倍的速度发展起来了,Metasploit为渗透测试者和研究员提供binary exploitation, payloads和post-exploitation payloads[4]这样的一个高端平台。由开发商和社区所开发的Metasploit 为一系列的操作系统,商业和开源软件提供exploit,一份exploit可以提供多种形式,但其最终目的仍然是明确的:控制程序执行流程。 有许多种可以充分利用漏洞的不同攻击方式,,不管是本地缓冲区溢出,堆污染,整数溢出,还是格式串漏洞,等等这些漏洞都可以采取在本地或远程执行攻击,这主要是依靠软件的漏洞及其功能。在Metasploit宝库中的每一个exploit都提供很多的payload选项,payload实际上是以机器码的形式在受害者的机器上运行的。Payload可以简单地添加用户到系统中,或者将VNC服务注入到受害者电脑的进程中。Metasploit对于大众的价值在于高级payload的延续性。Metasploit为用户提供简单接口以执行强大的exploit,甚至更为高级的payload,即使用户并不知道机器是如何被攻击的,也可以达到攻击目的。易用性,文档和资源均为用户提供方便,这也意味着一些攻击者可以使用Mestasploit去攻击网络。其中被攻击者广泛使用的payload就是Meterpreter。 Meterpreter(Meta Interpreter的简称)payload只存在攻击者主机的内存中,以免去攻击者读取磁盘数据。Metasploit将上传一份 DLL(Meterpreter)到远程主机,上传的DLL文件将存储在受害者主机的进程堆中。以传统方式上传的DLL文件将被写入到磁盘中,这是因为 LoadLibrary加载了模块,而模块只从磁盘或者网络共享里面加载。为了避开它,Metasploit hook 函数LoadLibrary所调用的隐含API,这些API如下:
● NtMapViewOfSection ● NtQueryAttributesFile ● NtOpenFile ● NtCreateSection ● NtOpenSection
这些钩子允许Meterpreter从内存中而非磁盘上被加载。加载后的Meterpreter为攻击者提供了很多选项,大家可以添加自定义脚本来扩展Meterpreter的功能[5]。
Meterpreter 一旦Meterpreter设置的shellcode被执行,而且Meterpreter已经加载,则便可以开始通讯。 Meterpreter的交互性和可扩展性对攻击者而言是最有价值的东西。本文是以攻击者为客户端,而受害者为服务端的角度来思考问题的。 Meterpreter的协议已被HD Moore和Skape很好的文档化了[6]。本文最终将利用下文提到的协议的优势来重现攻击的一个通讯过程。 Meterpreter使用的协议称为Type Length Value (TLV) 。type和length是4字节,而value是N字节。使用传统TLV协议的Meterpreter中有一附加说明,声称它已将TL调换为 length type value协议,但是Meterpreter文档的作者称他们将继续引用TLV作为其协议。 客户端先发送一个请求到服务端以指定一个type,这将告诉服务端如何去处理该请求,length和value,所有的这些将帮助服务端执行一些请求。使用TLV同种原则所构成的一个response:这个response拥有一个length,一个type及一个value,这个value也可以是其它 TLV。嵌套的TLV允许动态响应和描述复杂的数据结构。 理解客户端是如何向服务端发送请求最简单的方法就是举例,比如说客户端想要获得当前被攻击的进程的PID,那么客户端将构造一个type为 PACKET_TYPE_REQUEST,value为stdapi_sys_process_getpid的请求,这一字符串代表的是服务端揭露的方法。通过指定服务端处理请求的方法,服务端将调用此方法,并返回结果。这与远程过程调用(RPC)的工作原理有些相似,都是由客户端指定一个操作码(功能号码) ,由服务端调用,并封送返回结果。服务端一接收到请求,它将会寻找表中的方法。函数表的入口如下:
{ "stdapi_sys_process_getpid", { request_sys_process_getpid, { 0 }, 0 }, { EMPTY_DISPATCH_HANDLER }, }, 如果这样一种方法被请求,那么以上数组中的信息将描述方法名和被调用的函数指针。在这种情况下,客户端希望 request_sys_process_getpid被调用,服务端执行该函数并返回结果。由此产生的响应正是取证调查人员所感兴趣的地方。下面看一下 stdapi_sys_process_getpid 请求的回复内容,返回的结果是一个复杂的TLV Packet:
Table 1: TLV Packet from getpid request
读者可以看到,实际上回复值是由三个嵌套的TLV构成的。这是一个基本的回复,大部分response将会更加复杂,在嵌套的TLV中实际上是由一堆结果嵌套而成的。利用Meterpreter的协议及其易于理解的结构,是有可能通过分析残留在内存中的结构而重现攻击者的行为。
Metasploit Forensic Framework
Metasploit Forensic Framework (MSFF)是一个用于辅助进程攻击分析的工具集。在MSFF运行前,分析师必须先获得他们怀疑被攻击的进程,这些可以结合Memoryze和批处理脚本来完成。进程捕获也是很简单的: ProcessDD.bat –pid [process id] 进程一被捕获,MSFF即可运行,与写入到磁盘的文件进行比对,并记录每一文件所描述的被加载到进程地址空间的内存块。
MSFF工作原理
MSFF的工作原理主要是依据被释放的内存并没有真正地丢失或消除而进行的。当内存被释放时,它只是被标记为不可用而已,但这些内存页所包含的数据并没有被清除或清零。这也就意味着一名分析师可以追回和查看内存,并找到释放的内存页。 Meterpreter packet在内部调度,以指示正确地释放payload。Meterpreter将通过调用packet_transmit_response来响应 TLV,它将调用packet_transmit。这个函数实际上是用于发送TLV回复给客户端。响应包一发送,Meterpreter就会调用 destroy_packet去释放”payload”。在我们的例子中,它将会释放整个响应包。但是,释放内存并不意味着它会丢失和不可获取。 MSFF工程通过扫描每一块获取的内存块,然后查找攻击者在攻击过程中Meterpreter所发回的响应包中已知的“方法”字符串。 - priv_passwd_get_sam_hashes – 通知Meterpreter转存sam哈希值 - stdapi_sys_process_getpid – 检索当前被攻击的进程 - core_channel_write – 写回数据给Metasploit 控制台,当攻击者执行“execute –i” 命令时也会被使用 有很多是MSFF支持的,也有一些是不受支持的。MSFF工程扫描每个VAD中这些已知的字符串,如果找到,则开始分析TLV结构。由于TLV结构包含有type,以指示如何分析它的数据,MSFF利用这些信息恢复响应包。还因为Meterpreter调用回复方法来响应,这样 MSFF就可以知道攻击者请求后响应的结果了。所有的这些信息都是从内存中获取的,可用于重现所发生的攻击过程。
Figure 4: Acquired VAD from exploited processes
最后的步骤可参考上面的Figure 4,Figure 4是VAD的一部分,用于捕获Meterpreter所攻击的进程。回顾一下,MSFF扫描被调用的方法 stdapi_sys_process_get_pid。在这种情况下,该方法被发现了。继续分析这一特定内存区域,检索在Table 1中所看到的值:来自getpid请求的TLV Packet。
警告和陷阱
一个重要的警告和陷阱就是内存是不稳定的,易被改变。在任务繁忙的系统中,内存将被重复使用。Meterpreter没有释放它的数据包,但在 windows内存管理器并没有立即重复使用被释放的内存页。这就意味着释放后的内存可留在系统中较长时间,有各种可变因素可以影响到被释放的内存驻留在系统中的时间,但一般它在释放数小时之后仍可以查看。 在从某些被攻击的进程环境中获取内存就存在着一些问题。Metasploit提供三种不同类型的退出例程:SHE,进程和线程。如果攻击者是使用SHE或进程的退出例程,那么针对一个存在堆污染漏洞的浏览器的攻击时,它的整个进程内存在与Meterpreter断开套接字连接之后就会被清除。这就阻碍了浏览器进程内存的提取,因为它已经关闭了。在测试MS09 - 002 IE 7的初始化内存破坏漏洞时,如果攻击者使用了EXITFUNC变量来设置线程, 在Meterpreter套接字关闭之后,Internet Explorer进程将不会被终止,它仅是退出在攻击过程中所使用的线程。然而,相对受害者主机上的终端用户来说,这将会使IE的功能失效。但并非所有的 exploit都会终止当前被利用的进程。比如MS08-067,被攻击的svchost.exe进程内存中拥有Meterpreter客户端与服务端断开连接数小时后的数据。
结论
这里所讨论的技术和研究只是内存取证的一个开端,特别是如何更好地利用发现的人为产生的内存数据进行内存取证的技术。事实上, Windows内存管理器功能在释放内存页后,并没有马上清除,这对于取证分析很有帮助。这种行为也类似于传统文件系统取证。当一个文件被删除后,只是从链表中解链,但开始并没有被覆写,它允许分析人员在文件删除后数天之内进行数据恢复。这只是迈出了第一步,至少证明了在取证人员的工具箱中内存取证仍占有一席之地。在以后的研究当中,还有更多的工作要做,以便更好地了解释放内存的限制。
资料
1.http://www.mandiant.com/software/memoryze.htm 2.http://technet.microsoft.com/en-us/library/cc787565.aspx 3.http://www.metasploit.com/ 4.http://metasploit.com:55555/PAYLOADS 5.http://hick.org/code/skape/papers/remote-library-injection.pdf 6.http://www.nologin.org/Downloads/Papers/meterpreter.pdf
|