NSA武器库中的Eternalblue利用该bug,使得TRANS2_OPEN2命令可以传输大于0×10000字节的transaction数据。由于只有SMB_COM_NT_TRANS请求的TotalDataCount为4个字节,其它类型请求的TotalDataCount都为2个字节。因此漏洞利用需要先发送一个SMB_COM_NT_TRANS请求将TotalDataCount定义为大于0xFFFF字节,然后再发送SMB_COM_TRANSACTION2_SECONDARY请求,完成TRANS2_OPEN2命令中所有transaction数据的传输。
在前面的介绍(实现细节11)中已经提及,当WriteMode字段被设置为RAW_MODE时,SMB_COM_WRITE_ANDX命令也会采用transaction方式传递数据。这是一种非常有趣的情况,因为SrvSmbWriteAndX函数会利用下述代码向transacation中写入数据:
memmove(transaction->Indata, request->data, request->dataLength); transaction->InData += request->dataLength; //移动InData指针 transaction->DataCount += request->dataLength;需要注意的是,SrvSmbWriteAndX在向缓冲区中写入数据时,会移动InData的指针;而transaction secondary请求使用dataDisplacement字段设置在InData缓存区中写入数据的位置(而不移动InData指针)。
假设我们首先创建一个TotalDataSize设置为0×2000的transaction传输过程,MID与打开命名管道的FID保持一致。此时的内存布局如下所示(省略了无关的OutParameters和OutData):
+---------------+-----------------------------------------------------+ | TRANSACTION | transaction data buffer | +---------------+-----------------------------------------------------+ | InSetup | InParameters | InData | +-----------------------------------------------------+然后发送一个WriteMode设置为RAW_MODE、trans_data大小为0×100字节的SMB_COM_WRITE_ANDX命令。如果我们再向服务端发送dataDisplacement等于0x1f??的transaction secondary数据包,显而易见:
0x1f?? + 0×100 > 0×2000
写入数据就会超出原本申请的transaction data缓冲区的范围。如下所示:
+---------------+-----------------------------------------------------+ | TRANSACTION | transaction data buffer | +---------------+-----------------------------------------------------+ | InSetup | InParameters | | InData | +-----------------------------------------------------+这种越界写漏洞可以实现非常好的漏洞利用效果,但需要提前为上述SMB_COM_WRITE_ANDX命令提供一个有效的命名管道FID。而Vista之后系统,默认的Windows配置已经不允许匿名登陆(NULL)访问任何命名管道。
备注:NSA武器库中的Eternalromance和Eternalsynergy都利用这个bug实现了越界写的效果。另外,Eternalromance还利用Bug3来泄露transaction结构体的地址(只在win8之前系统有效)。而Eternalsynergy利用的是Bug5,并采用了一些技巧在Win8和Win2012中寻找具有NonPagedPoolExecute属性的内存页。两个工具还采用一种增大内存页的方式向我们展示了另外一种堆喷射的方法。
Bug7: SrvOs2FeaListSizeToNt中的类型分配错误SMB_COM_TRANSACTION2命令用于对文件���文件夹的拓展属性EA的名称/数值对进行编码,客户端的请求中使用了SMB_FEA数据结构:
SMB_FEA { UCHAR ExtendedAttributeFlag; UCHAR AttributeNameLengthInBytes; USHORT AttributeValueLengthInBytes; UCHAR AttributeName[AttributeNameLengthInBytes + 1]; UCHAR AttributeValue[AttributeValueLengthInBytes]; }通常在发送的SMB_COM_TRANSACTION2子命令请求中,含有承载多个SMB_FEA数据结构的FEA_LIST列表:
SMB_FEA_LIST { ULONG SizeOfListInBytes; UCHAR FEAList[]; }当服务端处理这些含有FEA_LIST的SMB_COM_TRANSACTION2子命令请求时,会将其转换为FILE_FULL_EA_INFORMATION数据结构的列表:
typedef struct _FILE_FULL_EA_INFORMATION { ULONG NextEntryOffset; UCHAR Flags; UCHAR EaNameLength; USHORT EaValueLength; CHAR EaName[1]; } FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;