黑基网 首页 资讯 安全圈 查看内容

EternalBlue(永恒之蓝)工具漏洞利用细节分析

2017-11-13 01:08| 投稿: lofor |来自: 互联网

摘要: 前言EternalBlue(永恒之蓝)据称是方程式组织在其漏洞利用框架中一个针对SMB服务进行攻击的模块,由于其涉及漏洞的影响广泛性及利用稳定性,在被公开以后为破坏性巨大的勒索蠕虫 WannaCry所用而名噪一时。360威胁情 ...

前言

EternalBlue(永恒之蓝)据称是方程式组织在其漏洞利用框架中一个针对SMB服务进行攻击的模块,由于其涉及漏洞的影响广泛性及利用稳定性,在被公开以后为破坏性巨大的勒索蠕虫 WannaCry所用而名噪一时。360威胁情报中心对于WannaCry的活动持续地进行着监控,我们看到的趋势是 WannaCry的感染量还在增加,说明作为蠕虫主要传播手段的EternalBlue相应的漏洞还大量存在着。但是,对于EternalBlue 这个攻击利器本身的技术分析在公开渠道上看到的讨论其实并不充分,本文尝试通过一个较完全的分析梳理相关的细节,揭示其成因和相应的利用技巧。

测试环境

对于EternalBlue的分析是在一个相对简单的环境中进行的,执行攻击的系统为一个Win7机器,目标机器也是 Win7 32位系统,没有安装EternalBlue相关的补丁,srv.sys文件的版本为 6.1.7601.17514,srvnet.sys的版本为 6.1.7601.17514 。本文中所有的调试器中代码截图都对应上述的版本,不同版本的文件在代码本身或偏移可能不同,但整体的执行逻辑应该差不多。

漏洞

根据我们的分析,EternalBlue达到其攻击目的事实上利用了3个独立的漏洞:第一个也就是 CVE-2017-0144被用于引发越界内存写;第二个漏洞则用于绕过内存写的长度限制;第三个漏洞被用于攻击数据的内存布局。下面重点介绍一下前两个漏洞,第三个漏洞会在内存布局的过程中提到。

漏洞1

首先是EternalBlue工具中使用到的主体漏洞,该漏洞也是Eternalblue的核心部分,编号为 CVE-2017-0144。漏洞通过SMB协议的SMB_COM_TRANSACTION2 命令触发,该命令说明如下所示:

当该数据包中包含对应的FEA LIST时,SMB服务中会将 FEA LIST转换为对应的NTFEA LIST,其对应的数据结构并不公开,如下所示为趋势团队分析出的对应的FEALIST 结构。

入口处理函数为SrvSmbOpen2,其中漏洞出现在函数SrvOs2FeaListToNt 中:

如下所示为对应的漏洞函数SrvOs2FeaListToNt,用于实现 FEA LIST转换为对应的NTFEA LIST,函数调用SrvOs2FeaListSizeToNt 计算 FEALIST的长度,但是该函数存在漏洞导致在特定的情况下,攻击者可以伪造超长的size,从而导致在之后的 SrvOs2FeaToNt 转换中导致 pool溢出。

进入导致漏洞的SrvOs2FeaListSizeToNt函数,该函数会计算对应的 FEA LIST的长度并随后对长度进行更新,该长度一开始为DWORD类型的,之后的长度更新代码中计算出的size 拷贝回去的时候是按 WORD进行的拷贝,此时只要原变量a中的初始值大于FFFF ,即为 10000+,该函数的计算结果就会增大。

该赋值中如下所示esi 变成了si,此时如果eax高位中的数据不为零,则将返回的超长的size 。

如下图所示为对应发送的该数据包,可以看到该请求数据包的长度为 103d0,其中对应的FEALIST的长度为10000。

如下图所示, eax为链表的开头,其指向了FEA LIST的总长度,即10000, esi为遍历之后的链表尾部,eax-esi=ff5d,为实际对应的长度,但是更新长度的mov 指令中 esi变成了si,由于eax 中的值为 10000 ,原本应该被赋值为ff5d的eax ,变成了 1ff5d 。

之后在紧接着的函数 SrvOsFeaToNt中,由于使用了错误的长度进行memmove从而导致溢出。

下图为其中的复制导致越界写,长度为a8,可以看到正常请求应该是在86535000这个srv.sys对象SMB buffer中,由于长度过长导致对srvnet.sys分配的buffer越界写。

Enternalblue 中通过内存布局,将srvnet对象buffer稳定的分配到srv 拷贝对象 buffer之后,如下图所示为越界写时的内存情况。

Srvnet 对象buffer中包含两个重要的域:

1. 一个指向指定结构(srvnet_recv)的指针(即上图中的8834e4c0,被ffdff020覆盖),该指针将会在smb(srnet)连接结束或断开时被用于寻址函数地址。

2. 一个用于接收缓冲区的MDL(即上图中的86546160,被ffdfef80覆盖)

因此覆盖并控制MDL将导致之后的tcp 栈实现任意写入伪造对象的操作,覆盖并控制该指针可用于将其指向一个攻击者控制的伪造对象,此时断开smb(srvnet)连接即可导致代码执行。

如下图所示,MDL复写为ffdfef80后,紧接着Eternalblue发送的shellcode就会被写入到ffdfef80+0×80的位置,即ffdff000。

可以看到此时的调用栈:

写入的地址ffdff000是系统预留的用于保存系统信息的地址,并且可执行。

被写入到 ffdff000地址的是一个srvnet_recv的结构(该结构不公开)和紧随其后的shellcode ,该结构用于 smb(srnet)结束或断开连接的时候通过SrvNetWskReceiveComplete调用 SrvNetCommonReceiveHandler 。SrvNetCommonReceiveHandler 根据srv_recv 中的指针此处为下图中的 poi (ffdff190(ffdff020 (被覆盖的对应指针) +0x16c )+4)获取到对应的函数并调用,地址即我们伪造的 shellcode 的地址( ffdff1f1 )。

漏洞2

如上述漏洞所示可以导致一次越界写,但其前提是FEA LIST的长度必须大于10000,通过分析可以发现FEA LIST只存在于SMB_COM_TRANSACTION2命令的子命令中,而该命令的数据结构如下:

TotalDataCount(数据包总长度)是USHOER类型的,即最大值只能为FFFF,那在这个地方 EternalBlue是如何发送的长度大于FFFF的SMB_COM_TRANSACTION2 子命令请求的呢?

通过抓包可以发现此处发送的并不是SMB_COM_TRANSACTION2子命令的请求包,而是SMB_COM_NT_TRANSACT子命令的请求包:

如下图所示SMB_COM_NT_TRANSACT子命令中TotalDataCount的类型为ULONG,支持发送大于FFFF长度的数据包。

但是SMB_COM_NT_TRANSACT本身是不支持FEA LIST的,这里就涉及到 EternalBlue 中使用到的第二个漏洞。

SMB的子命令中存在一个名为TRANSACTION系列的命令:

Ø  SMB_COM_TRANSACTION: 用于和邮槽、命名管道进行通信

Ø  SMB_COM_TRANSACTION2: 用于打开或创建一个共享文件或文件夹,设置它们的扩展属性

Ø  SMB_COM_NT_TRANSACT: 用于打开或创建一个文件或文件夹,并应用扩展属性EA或安全描述符SD

其中产生漏洞的即为对应的SMB_COM_TRANSACTION2命令。

对于TRANSACTION系列的命令如果发送的长度过大,SMB会将该请求包拆分成**Second的形式进行发送,如下所示为其相应的**Second系列的命令:

SMB_COM_TRANSACTION

SMB_COM_TRANSACTION_SECONDARY

SMB_COM_TRANSACTION2

SMB_COM_TRANSACTION2_SECONDARY

SMB_COM_NT_TRANSACT

SMB_COM_NT_TRANSACT_SECONDARY

服务端根据SMB请求头部的TIP, PID,UID,MID确定哪一个 **Second 属于对应的transtion,而服务端根据最后一个**Second 确定对应的 transtion 类型,即如果最后一个**Second为SMB_COM_TRANSACTION2_SECONDARY ,就按 SMB_COM_TRANSACTION2 来处理。

如下图为处理对应**Second的逻辑,对于一个transaction ,如果没有发送完,后续会跟上对应的**Second数据包,服务端不会检查对应的**Second类型,只要保证其 TIP ,PID,UID, MID 匹配,服务端就会将这些数据重新组装还原成一个 transaction,而类型由最后一个**Second 决定。

因此,为了发送一个长度为0×10000的SMB_COM_TRANSACTION2,首先发送一个长度为103d0(FEA LIST:1000)SMB_COM_NT_TRANSACT,之后发送一系列SMB_COM_TRANSACTION2_SECONDARY数据包,只要保证TIP,PID,UID,MID一致,服务端最后就会将其当做一个SMB_COM_TRANSACTION2来处理,而此时其长度103d0。

由于SMB会等待最后一个**SECOND数据包到来才生成最后的transaction ,因此EternalBlue可以在此期间发包对目标设备的内存进行部署,之后再发送最后一个数据包从而触发漏洞越界写。

内存布局的构建

如上述分析,利用漏洞会触发溢出导致越界写,而EternalBlue中对于该漏洞的利用思路和大多数的pool越界写是一致的:

1.      在内存中spray一系列srvnet的对象buffer

2.      释放掉其中的空间,以便于srv的对象buffer进行占位

3.      srv对象buffer占位

4.      发包越界写srvnet的对象buffer

5.      触发代码执行

srvnet对象spray

但是这里和一般的内核漏洞的利用存在一个很大的区别,就是我们的环境是远程的。通常的本地内核漏洞利用的时候我们可以从容地选择进行spray的内核对象,但是对于远程的环境而言,内核对象的选择及对应的控制就要小很多。

EternalBlue中用于被覆盖的对象为srvnetbuffer,其中的对象包含两个重要的结构:

1.      一个指向指定结构的指针,通过覆盖它可以将其指向一个伪造的结构,从而实现后续的代码执行。

2.      一个接受MDL的缓冲区,通过覆盖它可以保证将后续发送的伪造结构及shellcode写到指定的区域。

微软提供了SMB 2直接支持TCP的通信方式,可以通过该方式来创建srvnet 缓冲区。

如下图所示srvnet对象的spray过程,生成的大小依赖于前四字节。

srv对象spray

srv对象是通过释放后重申请的方式获取的地址空间,但是SMB中如何通过远程方式稳定的申请并释放一段pool内存了?这就涉及到EternalBlue中使用的第3个漏洞。

该漏洞出现在SMB_COM_SESSION_SETUP_ANDX命令中:

该命令的请求依赖于WordCount的值来确定具体的请求格式,当为12时格式如下图所示,当为13时红框中的变量会有所区别。

直接借用网上逆向简化后的一段代码,如下所示:如果发送的代码中WordConut为12,包含 CAP_EXTENDED_SECURITY字段,但却没有FLAGS2_EXTENDED_SECURITY字段,将会导致服务器将以处理13类型请求的方式去处理类型 12的请求包,从而进入错误的函数GetNtSecurityParameters流程中。

GetNtSecurityParameters会检查对应的请求中的参数,函数参数中的v70为通过 wordcount 和Bytecount计算出来的一个size。

GetNtSecurityParameters函数中的计算如下所示:

该参数返回后作为SrvAllocateNonPagedPool的参数分配一段pool 。

因此利用该漏洞将12类型的请求包通过13类型进行处理,由于两种类型的请求包格式不一致,通过控制请求包指定偏移的数据,即可以控制SrvAllocateNonPagedPool创建的pool的大小,可以使用以下的断点监控该过程:

bp GetNtSecurityParameters+0x1AC”.printf\”GetNtSecurityParameters1\\n\”;r;.echo;?cx-si+bx+1d;g;”

bp SrvAllocateNonPagedPool+0×10″.printf\”SrvAllocateNonPagedPool NonPageSize:%p\\n\”,ecx;g;”

bp SrvAllocateNonPagedPool+0x15C”.printf\”SrvAllocateNonPagedPool allocNopage:%p\\n\”,eax;g;”

bp BlockingSessionSetupAndX+0x7C0″.printf\”BlockingSessionSetupAndX double\\n\”;g;”

如下图所示即为通过断点监控到的非法size生成的过程,通过构造畸形数据包,包含数据87f8,漏洞触发后识别出该错误的偏移,计算最后会分配一段大小为 10fec大小的pool。

小编推荐:欲学习电脑技术、系统维护、网络管理、编程开发和安全攻防等高端IT技术,请 点击这里 注册黑基账号,公开课频道价值万元IT培训教程免费学,让您少走弯路、事半功倍,好工作升职加薪!



免责声明:本文由投稿者转载自互联网,版权归原作者所有,文中所述不代表本站观点,若有侵权或转载等不当之处请联系我们处理,让我们一起为维护良好的互联网秩序而努力!联系方式见网站首页右下角。


鲜花

握手

雷人

路过

鸡蛋

相关阅读

最新评论


新出炉

返回顶部