码迷,mamicode.com
首页 > 其他好文 > 详细

Eternalblue review

时间:2017-10-20 23:22:51      阅读:454      评论:0      收藏:0      [点我收藏+]

标签:构造   uri   结构   image   请求   函数参数   nts   cap   实现   

Eternalblue为方程式组织漏洞利用框架中一个针对smb协议进行攻击的模块,由于其稳定性及易用性,被勒索蠕虫Wanacry用于传播,网络上就Eternalblue使用的主要漏洞进行了分析,但是就整体利用并没有一个详细的说明,本文希望尽可能对Eternalblue的整个利用过程进行一个梳理。

环境

攻击机   win7 32

被攻击机 win7 32

         Srv.sys:6.1.7601.17514

    Srvnet.sys: 6.1.7601.17514

漏洞1

首先是Eternalblue工具中使用到的主体漏洞,该漏洞也是Eternalblue的核心部分,可以通过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分配的smb 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+0x80的位置,即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的子命令中存在一个名为transcation系列的命令

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

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

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

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

对于transcation系列的命令如果发送的长度过大,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决定。

 技术分享

因此为了发送一个长度为0x10000的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中用于被覆盖的对象为srvnet buffer

srvnet buffer中的对象包含两个重要的结构

  1. 一个指向指定结构的指针,通过覆盖它可以将其指向一个伪造的结构,从而实现后续的代码执行。
  2. 一个接受MDL的缓冲区,通过覆盖它可以保证将后续发送的伪造结构及shellcode写到指定的区域。

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

技术分享

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

技术分享

Srv对象spray

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

该漏洞出现在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+0x10 ".printf\"SrvAllocateNonPagedPool NonPageSize:%p\\n\",ecx;g;"

bp SrvAllocateNonPagedPool+0x15C ".printf\"SrvAllocateNonPagedPool alloc Nopage:%p\\n\",eax;g;"

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

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

通过断开对应的该命令请求,可以导致之前分配的10fec大小的pool被释放,从而在地址空间中生成一个hole,该hole之后会被srv对象buffer来填充。

现在知道如何在内存中稳定的spray一段连续的srvnet的对象buffer,以及如何开辟并释放一段指定大小的空间,内存布局的基本条件已经具备,可以看到具体的布局流程如下所示:

1.通过SMB_COM_NT_TRANSACT发送一段FEA LIST长度满足0x10000的数据包

2.发送后续的SMB_COM_TRANSACTION2_SECONDARY,这将导致smb服务将SMB_COM_NT_TRANSACT当做SMB_COM_TRANSACTION2处理,但是最后一个SMB_COM_TRANSACTION2_SECONDARY留置最后。

3.通过smb 2协议进行srvnet对象的spray

4.通过SMB_COM_SESSION_SETUP_ANDX漏洞在srvnet对象之后分配一段大小和srv对象大小几乎一致的pool内存

5.通过smb 2协议继续进行srvnet对象的spray,以确保srvnet位于srv对象之后

6.断开连接导致第四步开辟的pool内存释放,生成一个hole

7.发送最后一个SMB_COM_TRANSACTION2_SECONDARY,由于大小一致,该数据包会填补生成的hole,并触发漏洞导致之后的srvnet对象buffer中的MDL和指针被修改,此时后续发送的数据将拷贝到ffdff000的位置。

8.断开所有连接,触发srvnet_recv指向的shellcode执行

可以通过以下断点监控利用时内存的释放和分配(主要是srv,srvnet对象)

bp SrvAllocateNonPagedPool+0x10 ".printf\"SrvAllocateNonPagedPool NonPageSize:%p\\n\",ecx;g;"

bp SrvAllocateNonPagedPool+0x15C ".printf\"SrvAllocateNonPagedPool alloc Nopage:%p\\n\",eax;g;"

bp SrvFreeNonPagedPool+0x3 ".printf\"SrvFreeNonPagedPool free Nopage:%p\\n\",eax;g;"

 

bp BlockingSessionSetupAndX ".printf\"BlockingSessionSetupAndX\\n\";g;"

bp SrvNetAllocateNonPagedBufferInternal ".printf\"AllocateNonPaged NonPagedBufferSize:%p\\n\",poi(esp+8);g;"

bp SrvNetAllocateNonPagedBufferInternal+0x179 ".printf\"AllocateNonPaged NonPagedBufferAddress:%p\\n\",eax;g;"

bp SrvNetFreeNonPagedBufferInternal ".printf\"SrvNetFreeNonPagedBufferInternal free NonPageBufferAddress:%p\\n\",poi(esp+4);g;"

ba e1 srvnet!SrvNetWskReceiveComplete+0x13 ".if(poi(esi+0x24) == ffdff020) {} .else {gc}"

如下图所示即为整体监控到的数据包于内存中的布局情况,其中867bb000处为对应的srv buffer对象,之后867cc000上的srvnet buffer对象将会被覆盖如下所示:

 技术分享

 

以上为Eternalblue利用过程中内存布局及对应发送数据包的一个概述,但是其内部其实还有一些细节可供深入挖掘。

由于作者水平有限,有什么错误欢迎大家指正。

参考链接

http://bobao.360.cn/learning/detail/3738.html

https://github.com/worawit/MS17-010

http://blog.trendmicro.com/trendlabs-security-intelligence/ms17-010-eternalblue/

 

Eternalblue review

标签:构造   uri   结构   image   请求   函数参数   nts   cap   实现   

原文地址:http://www.cnblogs.com/goabout2/p/7701871.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!