Windows搜索服务(WSS)是windows的一项默认启用的基本服务。允许用户在多个Windows服务和客户端之间进行搜索。 Windows搜索处理内存中的对象时,存在远程执行代码漏洞,成功利用此漏洞的攻击者可以控制受影响的系统。虽然漏洞与SMB协议本身无关,但攻击者可SMB目标作为攻击媒介,因此该漏洞面临着与Wannacry类似的大规模利用风险。CNVD对该漏洞的技术评级为“高危”。
Windows Search是一个桌面搜索平台,具备对大多数常见文件类型和数据类型的即时搜索功能。 其主要组件是WSearch Windows服务,它负责索引、组织和提取有关本地文件系统的信息。 此外,它还实现了Generic Search Service(GSS),可以为搜索查询提供结果所需的后端功能。客户端使用Windows Search Protocol(WSP)向托管GSS的服务器发出查询。 WSP依赖于服务器消息块(SMB)命名管道协议进行消息传输和身份验证。
使用WSP的最小搜索查询可能类似于以下流程:
[ Client ] --------------------> [ Server ] - CPMConnectIn [ Client ] <-------------------- [ Server ] - CPMConnectOut [ Client ] --------------------> [ Server ] - CPMCreateQueryIn [ Client ] <-------------------- [ Server ] - CPMCreateQueryOut [ Client ] --------------------> [ Server ] - CPMSetBindingsIn request [ Client ] <-------------------- [ Server ] - CPMSetBindingsIn response [ Client ] --------------------> [ Server ] - CPMGetRowsIn [ Client ] <-------------------- [ Server ] - CPMGetRowsOut [ Client ] --------------------> [ Server ] - CPMGetFreeCursorIn [ Client ] <-------------------- [ Server ] - CPMGetFreeCursorOut [ Client ] --------------------> [ Server ] - CPMDisconnect
CPMConnectIn消息开始客户端和服务器之间的会话,CPMCreateQueryIn包含规范并创建新查询,CPMSetBindingsIn指定如何在CPMGetRowsOut中构建搜索结果,CPMGetRowsIn从查询中请求数据行。
所有的WSP消息以一个16字节的头部开始,其结构如下:
Offset Size (bytes) Field -------------------------------------------- 0x00 0x4 _msg 0x04 0x4 _status 0x08 0x4 _ulChecksum 0x0c 0x4 _ulReserved2
_msg字段标识标头部后面的消息类型,_status字段包含所请求操作的状态并由服务器填充,_ulChecksum包含从_ulReserved2字段后面开始的消息的校验和。跟本漏洞相关的是CPMCreateQueryIn消息,故本文暂且重点关注该消息。 此消息创建一个新的搜索查询,并具有以下结构:
Offset Size (bytes) Field -------------------------------------------------------------------- 0x00 0x4 Size 0x04 0x1 CColumnSetPresent 0x05 0x3 paddingCColumnSet 0x08 var (w) ColumnSet 0x08 + w 0x1 CRestrictionPresent 0x09 + w var (x) RestrictionArray 0x09 + w + x 0x1 CSortSetPresent 0x0a + w + x 0x3 paddingCCortSet 0x0d + w + x var (y) SortSet 0x0d + w + x + y 0x1 CCategorizationSetPresent 0x0e + w + x + y 0x3 paddingCCategorizationSet 0x11 + w + x + y var (z) CCategorizationSet 0x11 + w + x + y + z 0x14 RowSetProperties 0x25 + w + x + y + z var (m) PidMapper 0x25 + w + x + y + z + m var (n) GroupArray 0x25 + w + x + y + z + m + n 0x4 Lcid
从上面的结构中可以看出,有很多字段数值大小不是固定的,这对后续的流量监测可能造成很大困难。
在上面的结构中,需要重点关注的字段是CRestrictionPresent和RestrictionArray。 前者标识了RestrictionArray字段是否存在,后者包含描述查询命令树的CRestrictionArray结构。 命令树是为搜索查询指定的限制和排序顺序的组合。 CRestrictionArray具有以下结构:
Offset Size(bytes) Field ------------------------------------------- 0x00 0x1 count 0x01 0x1 isPresent 0x02 0x3 padding 0x05 var Restriction
isPresent字段标识Restriction字段是否存在且Restriction字段是否包含CRestriction结构。 CRestriction在查询命令树中包含限制节点,并具有以下格式:
Offset Size(bytes) Field ------------------------------------------ 0x00 0x4 ulType 0x04 0x4 Weight 0x08 var Restriction
ulType标识Restriction字段中存在的限制结构的类型。 此漏洞涉及具有指定CPropertyRestriction的ulType为RTProperty(0x5)的CRestrictions。 某些CRestriction类型可以包含嵌套的CRestrictions,形成一个限制树; 因此,CPropertyRestriction可以嵌入以下任何限制中:
上述列表中的限制具有以下结构:
CNodeRestriction: Offset Size(bytes) Field ---------------------------------------------------------------- 0x00 0x4 cNode (number of structures in paNode) 0x04 var paNode (array of CRestriction structures) CVectorRestriction: Offset Size (bytes) Field ------------------------------------------------------------ 0x00 var (n) pres (CNodeRestriction structure) 0x00 + n 0x3 padding 0x03 0x4 ulRankMethod CCoercionRestriction: Offset Size (bytes) Field ------------------------------------------------------- 0x00 0x4 flValue 0x04 var childRes (CRestriction structure)
带注释的字段可以包含更多限制,这些限制也可以包含嵌套限制,从而形成树。 CPropertyRestriction结构包含从每一行获取的属性,比较运算符和常量。 对于每一行,将行中特定属性返回的值与常量进行比较,以确定它是否具有指定的关系。 此限制具有以下结构:
Offset Size (bytes) Field ------------------------------------------ 0x00 0x4 relop 0x04 var (m) Property 0x04 + m var (n) prval 0x04 + m + n 0x3 padding 0x07 + m + n 0x4 lcid
relop字段标识比较的类型,例如, 大于,小于,正则表达式等。属性字段标识要匹配的属性,而prval字段指定与属性相关的值。 prval字段包含一个CBaseStorageVariant项,它具有以下结构:
Offset Size (bytes) Field ------------------------------------------ 0x00 0x2 vType 0x02 0x1 vData1 0x03 0x1 vData2 0x04 var vValue
vType字段标识存储在vValue中的值的类型。 此漏洞涉及VT_LPWSTR vType,该vType用于存储以null结尾的Unicode字符串。
当服务器收到CPMCreateQueryIn消息时,它会解析RestrictionArray并为每个限制实例化相关对象。如果服务解析ulType为0x5的CRestriction,对应于CPropertyRestriction,则解组prval字段并实例化CBaseStorageVariant对象。如果CPropertyRestriction的relop字段与0x6匹配,表示正则表达式比较,则服务开始将正则表达式解析为确定性有限自动机(DFA)。
但是,在解析正则表达式之前,服务无法验证CBaseStorageVariant对象的类型是否为VT_LPWSTR,这是一个以null结尾的Unicode字符串。如果类型不是VT_LPWSTR,则会发生类型混淆。
远程未经身份验证的攻击者可以通过向目标服务器发送恶意CPMCreateQueryIn消息来利用这些漏洞。成功利用可能会导致在SYSTEM上下文中的目标服务器上执行远程代码。
需要注意,SMB和WSP中的所有多字节整数都以little-endian字节顺序存储
使用的dll版本为7.0.7601.23861
CPropertyRestriction::CPropertyRestriction(long, class PDeSerStream &):
.text:6EC88B61 push ebx ; struct PDeSerStream * .text:6EC88B62 lea ecx, [ebp+var_20] .text:6EC88B65 call ??0CStorageVariant... ; unmarshall prval .text:6EC88B6A push eax .text:6EC88B6B mov ecx, edi .text:6EC88B6D mov byte ptr [ebp+var_4], 3 .text:6EC88B71 call ??4CStorageVariant... ; CStorageVariant::operator=
Parse(const struct CRestriction , struct CTimeLimit ):
.text:6ED350B3 cmp eax, 6 ; eax contains relop, check if relop indicates regexp .text:6ED350B6 jnz short loc_6ED350DE .text:6ED350B8 push 40h ; unsigned int .text:6ED350BA call ?ciNew@@YGPAXI@Z ; ciNew(uint) .text:6ED350BF mov [ebp+arg_0], eax .text:6ED350C2 mov ecx, [esi+14h] .text:6ED350C5 mov edx, [esi+10h] .text:6ED350C8 push ecx .text:6ED350C9 push edx .text:6ED350CA push [ebp+arg_4] .text:6ED350CD mov ecx, eax .text:6ED350CF push esi .text:6ED350D0 mov byte ptr [ebp+var_4], 7 .text:6ED350D4 call ??0CRegXpr@@QA... ; CRegXpr(), 解析正则表达式
CRegXpr::CRegXpr(class CInternalPropertyRestriction *, class CTimeLimit &, unsigned long, unsigned long):
.text:6ED37ABC push 0A8h ; unsigned int .text:6ED37AC1 call ?ciNew@@YGPAXI@Z ; ciNew(uint) .text:6ED37AC6 mov [ebp+var_7C], eax .text:6ED37AC9 push [ebp+var_78] ; int .text:6ED37ACC mov ecx, [esi+20h] .text:6ED37ACF push 0 ; int .text:6ED37AD1 push [ebp+arg_4] ; int .text:6ED37AD4 mov byte ptr [ebp+var_4], 6 .text:6ED37AD8 push ecx ; unsigned __int16 * .text:6ED37AD9 mov ecx, eax .text:6ED37ADB call ??0CDFA@@Q... ; CDFA::CDFA(), 不检测类型就直接解析vValue
CNFA::CNFA(unsigned __int16 *, int, int):
.text:6AF2781E mov dx, [eax] ; eax指向VT_LPWSTR data .text:6AF27821 inc eax .text:6AF27822 inc eax .text:6AF27823 cmp dx, di .text:6AF27826 jnz short loc_6AF2781E
Offset Size (bytes) Field ----------------------------------------------------------- 0x00 0x1 WordCount 0x01 0x1 AndXCommand 0x02 0x1 AndXReserved 0x03 0x2 AndXOffset 0x04 0x1 Reserved 0x05 0x2 NameLength 0x07 0x4 Flags 0x0b 0x4 RootDirectoryFID 0x0f 0x4 DesiredAccess 0x13 0x8 AllocationSize 0x1b 0x4 ExtFileAttributesMicrosoft Research Service 20 0x1f 0x4 ShareAccess 0x23 0x4 CreateDisposition 0x27 0x4 CreateOptions 0x2b 0x4 ImpersonationLevel 0x2f 0x1 SecurityFlags 0x30 0x2 ByteCount 0x32 var FileName
需要对所有SMB_COM_NT_CREATE_ANDX
命令中的FileName字段进行检测,查看是否存在Unicode编码的 "\MsFteWds" 。
对于相同的“\ MsFteWds”值,检测设备还必须检查能够打开命名管道的以下任何不常见命令的Name / FileName字段:
• SMB_COM_NT_TRANSACT with NT_TRANSACT_CREATE subcommand
• SMB_COM_TRANSACTION2 with TRANS2_OPEN2 subcommand
• SMB_COM_OPEN (deprecated)
• SMB_COM_OPEN_ANDX (deprecated)
• SMB_COM_TRANSACTION with TRANS_CALL_NMPIPE subcommand (obsolescent)
如果找到打开上述“\ MsFteWds”管道的任何命令,则设备必须继续检查此会话中的任何后续SMB1命令,并查找能够写入命名管道的命令。 这些命令包括:
• SMB_COM_WRITE
• SMB_COM_WRITE_AND_UNLOCK
• SMB_COM_WRITE_RAW
• SMB_COM_WRITE_MPX
• SMB_COM_WRITE_AND_CLOSE
• SMB_COM_WRITE_ANDX
• SMB_COM_WRITE_PRINT_FILE
• SMB_COM_TRANSACTION (TRANS_RAW_WRITE_NMPIPE)
• SMB_COM_TRANSACTION (TRANS_WRITE_NMPIPE)
如果找到上述数据,检测设备必须解析这些结构以获得发送到命名管道的数据。获得数据后,必须将此数据解析为WSP消息。
3.WSP消息的解析
设备必须检查CRestrictionPresent是否包含非零值,如果是,则根据以下结构解析RestrictionArray:
Offset Size (bytes) Field ------------------------------------------- 0x00 0x1 count 0x01 0x1 isPresent 0x02 0x3 padding 0x05 var Restriction
检测设备必须检查isPresent字段的值为0x1,如果相等,则将Restriction字段解析为CRestriction结构数组,其数量与count字段相等。 必须按如下方式解析CRestriction结构:
Offset Size (bytes) Field ------------------------------------------ 0x00 0x4 ulType 0x04 0x4 Weight 0x08 var Restriction
ulType标识Restriction字段中存在的限制结构的类型。 设备必须查找ulType为RTProperty(0x5)的CRestriction节点,对应于CPropertyRestriction。 请注意,有几个限制允许嵌套限制,其中可能出现CPropertyRestriction。 因此,设备还必须解析这些限制及其相应的字段,可能包含其他限制并找到嵌套的CPropertyRestrictions。 以下是包含嵌套限制的限制的ulType值列表:
• RTAnd (0x1), Restriction contains a CNodeRestriction structure
• RTOr (0x2), Restriction contains a CNodeRestriction structure
• RTNot (0x3), Restriction contains a CRestriction structure
• RTVector (0x7), Restriction contains a CVectorRestriction structure
• RTCoerce_Add (0xA), Restriction contains a CCoercionRestriction structure
• RTCoerce_Multiply (0xB), Restriction contains a CCoercionRestriction structure
• RTCoerce_Absolute (0xC), Restriction contains a CCoercionRestriction structure
上述列表中的限制的结构在前面已经给出,根据之前给出的相关结构,检测设备必须解析可能包含其他限制的限制的相关字段。
如果设备找到嵌套的CRestriction,则它必须递归检查ulType for RTProperty(0x5)或任何可能的递归类型。 此外,如果设备找到嵌套的CNodeRestriction,它必须检查paNode数组中的每个CR限制,查找等于RTProperty和递归类型的ulType值。 换句话说,检测设备必须检查每个嵌套节点。
如果检测设备找到ulType值为0x5的CRestriction节点,则设备必须将Restriction字段解析为CPropertyRestriction,其结构在前面也已经给出。
下一步,设备必须检查relop字段并检查其值是否等于0x6,可以使用正则表达式比较。 如果找到,则设备必须再解析prval字段。
检测设备必须检查vType字段并确保它等于0x1F(VT_LPWSTR)。 如果不相等,则应认为该部分流量为攻击流量。
以上只是个人综合其他前辈的经验进行的分析结果,可能存在偏差或错误。这个漏洞需要了解的东西比较多,分析起来比较麻烦。而且以上分析仅仅针对SMBv1的情况,对于SMBv2和SMBv3的情况尚未分析完毕,仍需继续努力啊。欢迎各位师傅前辈指导交流。