[译者注] 在实际环境中,可以构造TRANS_PEEK_NMPIPE命令请求数据包,保证MaxParameterCount、MaxDataCount满足二者之和大于0×10400,MaxDataCount+16小于0×10400。如果目标主机没有安装MS17-010补丁,则会返回一个0xC0000205错误码;如果模板主机已经修复了这个漏洞,,则响应给客户端的内容就不是0xC0000205错误码,而是由InSetup决定。因此可以通过检查TRANS_PEEK_NMPIPE命令响应回来的数据包是否为0xC0000205错误码来判断漏洞是否被修补。
Bug3: 允许Transaction响应数据长度大于申请的缓冲区长度SrvCompleteExecuteTransaction函数用于向客户端发送transaction响应,但期间并没有检查ParameterCount/DataCount是否大于MaxParameterCount/MaxDataCount。因此SrvCompleteExecuteTransaction有可能将缓冲区外的内存数据返回给客户端,从而会导致信息泄露。
要想利用这个bug,可以构造一个满足bug2的TRANS_PEEK_NMPIPE子命令,将MaxParameterCount设置为一个很大的数值,MaxDataCount只设置为1。如果transaction响应数据的长度(DataCount)大于MaxDataCount,SrvCompleteExecuteTransaction函数就会将OutData缓冲区及其之后的数据返回给客户端。
[译者注] bug2允许返回给客户端的OutData指针可以指向OutData缓冲区起始地址之后的内存位置,bug3允许返回的缓冲区大小可以超过MaxDataCount规定的长度。这两个bug,一个控制返回数据的起始地址,一个控制返回数据的长度。
此时transaction缓冲区如下所示:
+---------------+-----------------------------------------------------+ | TRANSACTION | transaction data buffer | +---------------+-----------------------------------------------------+ | InSetup | InParameters | InData | | +-----------------------------------------------------+------------+ | OutParameters |OutData| OOB read | +-----------------------------------------------------+------------+NSA武器库中的Eternalromance就采用bug2和bug3实现了信息泄露。有趣的是,自从win8发布伊始,这个bug就已经在win8及其之后的系统中被修复了。用于win8之前系统的MS17-010补丁,修复这个bug所采用的代码和win8中的代码就是一样的。
[译者注] 为何微软之前已经知道该漏洞的存在,却没有修复?细思甚恐。
由于NSA Eternalromance需要利用这个bug来泄露TRANSACTION结构体的地址,因而它无法在win8之后系统中实现利用。
Bug4: 允许ParameterCount/DataCount之和大于TotalParameterCount/TotalDataCount当发送SMB_COM_*_SECONDARY命令时,服务端通过检查displacement的值和trans_data的长度,以确保写入内存的数据不会超出申请的缓冲区大小。但期间并没有检查所有接收的ParameterCount/DataCount之和是否大于TotalParameterCount/TotalDataCount。
举例说明:假设一个transaction的TotalDataCount等于0×20。第一个请求发送0×18字节的数据,DataCount为0×18;第二个请求发送0×10字节的数据,DataCount就变成了0×28。
通常情况下,这个bug没有什么价值,但结合下面的bug5就能实现漏洞利用。
Bug5: 允许Transaction secondary请求在服务端开始处理transaction后才被接收和处理如果发送一个设置AllDataReceived字段的transaction secondary请求,服务端默认不作任何处理,直接返回一个错误。
对于需要多个数据包才能完成传输的transaction请求而言,服务端会在处理transaction之前设置好AllDataReceived字段,具体会在SrvSmbTransactionSecondary或SrvSmbNtTransactionSecondary函数中完成。但如果transaction在一个SMB消息中就能完成传输,服务端并不会去设置AllDataReceived。这就可能存在下述漏洞:
在服务端正在处理transaction或正在发送响应数据给客户端期间,可以通过发送一个transaction secondary请求来修改InParamter/InData缓冲区和ParameterCount/DataCount字段的内容。
[译者注] 没有设置AllDataReceived的话,表示服务端还可以继续接收Transaction请求,并将参数和数据存入InParameters和InData缓冲区中,ParameterCount/DataCount字段依旧会相应增加。
1、利用该漏洞的第一种场景