SrvOs2FeaListToNt函数会通过如下伪代码完成转换:
SrvOs2FeaListToNt() { outputLen = SrvOs2FeaListSizeToNt(feaList); output = SrvAllocateNonPagedPool(outputLen); // start copy all FEA data to output in a list of FILE_FULL_EA_INFORMATION format }SrvOs2FeaListToNt先调用SrvOs2FeaListSizeToNt,根据原始FEA_LIST计算出FILE_FULL_EA_INFORMATION列表缓冲区长度,然后调用SrvAllocateNonPagedPool申请新的缓冲区,最后将所有SMB_FEA数据以FILE_FULL_EA_INFORMATION格式拷贝到新的缓冲区。漏洞出现在用于计算新缓冲区长度的SrvOs2FeaListSizeToNt函数:
SrvOs2FeaListSizeToNt(feaList) { outputLen = 0; foreach (fea in feaList) { if (IsFeaDataOutOfBound(fea, feaList)) { // 缩小FEAfeaList.SizeOfListInBytes的范围只在合法的FEA中,因此拷贝步骤不会再检查其合法性 // feaList.SizeOfListInBytes定义为DWORD但却以WORD类型设置,因此HIDWORD永远不会被修改 (WORD) feaList.SizeOfListInBytes = Pos(fea) - Pos(feaList); return outputLen; } outputLen += GetNtLengthForFea(fea); } return outputLen; }根据上面伪代码的描述,如果发送一个feaList.SizeOfListInBytes为0×1000字节,但有效的FEA条目却小于0×1000字节(假设为0×4000)的请求。经过上述错误类型的长度计算,feaList.SizeOfListInBytes就变成了0×14000(因为HIDWORD没有被修改而Pos(fea) – Pos(feaList)得到的结果为0×4000)。后续拷贝SMB_FEA数据到输出区域时,就会导致缓冲区溢出。
要想成功实现利用,需要发送一个大于0×10000字节的transaction data,但FEA_LIST结构只在SMB_COM_TRANSACTION2命令中存在,TotalDataCount字段类型是USHORT(最大值为0xFFFF),因此我们需要利用Bug6(借助SMB_COM_NT_TRANS命令)来发送一个大于0×10000字节的FEA_LIST。
所需条件最少的漏洞利用途径是采用TRANS2_OPEN2子命令。处理该命令的SrvSmbOpen2函数,在权限检查之前会调用SrvOs2FeaListToNt函数转换FEA_LIST列表。因此,客户端只需访问服务端任意一个共享(IPC$是最好的选择),然后发送符合上述要求的transaction命令即可。
需要注意的是,Win8以上操作系统默认不允许匿名连接访问IPC$(IPC$可以连接上,但大部分transaction命令都无法使用)。
Bug8: SrvOs2GeaListSizeToNt中的类型分配错误该bug和bug7类似,只是出现在与上述不同的SrvOs2GeaListSizeToNt函数。要想利用,必须提供有效的FID才行。
Bug9: SESSION_SETUP_AND_X请求格式混淆漏洞该bug在MS17-010补丁中并没有被修复,将它放在这,是因为NSA武器库借助了该bug来实现漏洞的利用。该Bug本身只能欺骗服务端,来申请一个大的非分页内存池(小于0×20000字节),来存储客户端信息。
在NT LM 0.12中,包含两种格式的SMB_COM_SESSION_SETUP_ANDX请求。第一种格式:
SMB_Parameters { UCHAR WordCount; //13 Words { UCHAR AndXCommand; UCHAR AndXReserved; USHORT AndXOffset; USHORT MaxBufferSize; USHORT MaxMpxCount; USHORT VcNumber; ULONG SessionKey; USHORT OEMPasswordLen; USHORT UnicodePasswordLen; ULONG Reserved; ULONG Capabilities; } } SMB_Data { USHORT ByteCount; Bytes { UCHAR OEMPassword[]; UCHAR UnicodePassword[]; UCHAR Pad[]; SMB_STRING AccountName[]; SMB_STRING PrimaryDomain[]; SMB_STRING NativeOS[]; SMB_STRING NativeLanMan[]; } }该请求用于LM和NTLM的身份认证。
另外一种格式:
SMB_Parameters { UCHAR WordCount; //12 Words { UCHAR AndXCommand; UCHAR AndXReserved; USHORT AndXOffset; USHORT MaxBufferSize; USHORT MaxMpxCount; USHORT VcNumber; ULONG SessionKey; USHORT SecurityBlobLength; ULONG Reserved; ULONG Capabilities; } } SMB_Data { USHORT ByteCount; Bytes { UCHAR SecurityBlob[SecurityBlobLength]; SMB_STRING NativeOS[]; SMB_STRING NativeLanMan[]; } }该请求用于NTLMv2(NTLM SSP)的身份认证。
需要注意的是,两种格式的WordCount是不同的(第一种格式为13,第二个格式为12)。