010补丁对比发现的九个漏洞(7)

在服务端发送响应数据给客户端期间,向其发送特定的transaction secondary请求(将DataCount修改为超出OutData缓冲区的长度)。结果就会导致,服务端将OutData缓冲区外的内存数据作为响应发送给客户端(类似于bug3)。

但这种利用方法所需条件非常苛刻,必须保证服务端在发送响应数据之前,接收并完成对transaction secondary请求的处理。因此这种场景下看起来很难成功实现利用。

不过NSA武器库中的Eternalchampion和Eternalsynergy却采用了一种非常巧妙的方法来满足上述利用条件。

为了实现SMB登录,客户端会向服务端发送一个SMB_COM_SESSION_SETUP_ANDX请求。请求中包含了用于定义客户端能够接收消息最大字节数的MaxBufferSize字段。

如果transaction响应消息的大小超过了MaxBufferSize字段,服务端就会将整个响应消息分片为多个数据包发送给客户端。为了保证能够连续发送这些数据包,服务端会增加调用RestartTransactionResponse函数的任务队列。另外,该函数并没有检查MaxParameterCount和MaxDataCount是否合法。

根据以上描述,NSA采用了如下利用方式:

先向服务端发送一个携带特定MaxBufferSize字段的SMB_COM_SESSION_SETUP_ANDX登录请求,然后构造两个请求:一个完整的NT_TRANS_RENAME请求(其响应数据长度大于MaxBufferSize);一个NT_TRANS_RENAME secondary请求(其中的trans_data长度就是要泄露的字节数)。最后,将这两个请求通过一个TCP数据包发送给服务端。

由于服务端同时接收了位于同一个数据包的NT_TRANS_RENAME和NT_TRANS_RENAME secondary请求,因此服务端在发送完NT_TRANS_RENAME响应的第一部分数据之后,服务端队列会先处理NT_TRANS_RENAME secondary请求,再调用RestartTransactionResponse函数发送NT_TRANS_RENAME响应的剩余数据。由于Bug4的存在,在处理NT_TRANS_RENAME secondary请求时,DataCount数值会相应增加(而不会去检查其是否大于TotalDataCount)。这就导致后续服务端发送的transaction响应的剩余内容会携带OutData缓冲区外的内存数据。

Eternalchampion和Eternalsynergy都利用该bug实现信息的泄露。但不知何种原因,二者使用了不同的参数。

2、利用该漏洞的第二种场景

在服务端处理transaction期间,向其发送一个transaction secondary请求。不过很难在服务端处理transaction期间找到能够一种同时处理transaction secondary请求的利用途径。也很难满足“保证先处理完transaction secondary请求,再将上个transaction请求的响应数据返回给客户端”这一苛刻条件。

NSA武器库中的Eternalchampion采用设置SMB_INFO_IS_NAME_VALID查询级别的TRANS2_QUERY_PATH_INFORMATION子命令来实现该漏洞的利用。

[译者注] TRANS2_QUERY_PATH_INFORMATION子命令用于查询指定文件或文件夹中包含的信息,可以通过设置SMB_Data.Trans2_Parameters.InformationLevel字段来指定查询信息的级别。

如果信息级别设置为SMB_INFO_IS_NAME_VALID,SrvSmbQueryPathInformation处理函数就会修改InData指针,使其指向在栈中申请的UNICODE_STRING结构体。如果此时服务端能够在Transaction处理完成之前,转去处理transaction secondary请求,那么保存着EIP/RIP的栈内存就会被transaction secondary请求中包含特定偏移的trans_data和dataDisplacement所覆盖。(也就是说,我们可以控制栈中包含函数返回地址。)

由于栈中的偏移总是固定的,因此NSA Eternalchampion这种利用方式并不会导致目标主机出现崩溃。

备注:在SrvSmbWriteAndX函数中也发现了针对该bug的修复补丁。

Bug6: 允许Transaction secondary请求设置为任意transaction类型

通常情况下,如果第一个SMB数据包没有完成transaction数据的传输,后续数据包必须满足如下条件:

* SMB_COM_TRANSACTION后必须跟着SMB_COM_TRANSACTION_SECONDARY * SMB_COM_TRANSACTION2后必须跟着SMB_COM_TRANSACTION2_SECONDARY * SMB_COM_NT_TRANS后必须跟着SMB_COM_NT_TRANS_SECONDARY

但实际上,服务端并没有对Secondary数据包的类型进行检查。因此,可以通过发送任意类型的transaction secondary命令来完成transaction数据的传输,只需保证TID、UID、PID和MID匹配即可。

别忘了,服务端根据最后一个SMB_COM_*_SECONDARY数据包判断transaction命令的类型,因此通过最后一个Secondary请求,我们可以将任意transaction类型转变为SMB_COM_TRANSACTION或SMB_COM_TRANSACTION2类型。由于SMB_COM_NT_TRANS需要通过Function字段确定子命令类型(另外两个命令没有Function字段),故无法将非SMB_COM_NT_TRANS类型转换为SMB_COM_NT_TRANS类型。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/2fdecb1a7e0d23e78a1017478a1e4d25.html