|
CVE-2017-8620:Windows Search远程代码执行漏洞简单分析及流量侧检测防御思路漏洞描述[table][tr][td]
1
2[/td][td]
Windows搜索服务(WSS)是windows的一项默认启用的基本服务。允许用户在多个Windows服务和客户端之间进行搜索。
Windows搜索处理内存中的对象时,存在远程执行代码漏洞,成功利用此漏洞的攻击者可以控制受影响的系统。虽然漏洞与SMB协议本身无关,但攻击者可SMB目标作为攻击媒介,因此该漏洞面临着与Wannacry类似的大规模利用风险。CNVD对该漏洞的技术评级为“高危”。信息搜集
- 漏洞文件:tquery.dll
- 漏洞函数:CRegXpr::CRegXpr()数据对象:一个CPropertyRestriction结构
漏洞原理分析背景知识
- Windows Search
- MS-CIFSMS-SMB
因为是Windows Search的一个漏洞,需要对Windows Search具备一定的了解,此漏洞使用的SMB的途径,所以也要对SMB有一定的了解。
[table][tr][td]
1[/td][td]
Windows Search是一个桌面搜索平台,具备对大多数常见文件类型和数据类型的即时搜索功能。 其主要组件是WSearch Windows服务,它负责索引、组织和提取有关本地文件系统的信息。 此外,它还实现了Generic Search Service(GSS),可以为搜索查询提供结果所需的后端功能。客户端使用Windows Search Protocol(WSP)向托管GSS的服务器发出查询。 WSP依赖于服务器消息块(SMB)命名管道协议进行消息传输和身份验证。Windows Search Protocol使用WSP的最小搜索查询可能类似于以下流程:[table][tr][td]
1
2
3
4
5
6
7
8
9
10
11[/td][td]
[ Client ] --------------------> [ Server ] - CPMConnectIn
[ Client ] [ Server ] - CPMCreateQueryIn
[ Client ] [ Server ] - CPMSetBindingsIn request
[ Client ] [ Server ] - CPMGetRowsIn
[ Client ] [ Server ] - CPMGetFreeCursorIn
[ Client ] [ Server ] - CPMDisconnectCPMConnectIn消息开始客户端和服务器之间的会话,CPMCreateQueryIn包含规范并创建新查询,CPMSetBindingsIn指定如何在CPMGetRowsOut中构建搜索结果,CPMGetRowsIn从查询中请求数据行。
所有的WSP消息以一个16字节的头部开始,其结构如下:[table][tr][td]
1
2
3
4
5
6[/td][td]
Offset Size (bytes) Field
--------------------------------------------
0x00 0x4 _msg
0x04 0x4 _status
0x08 0x4 _ulChecksum
0x0c 0x4 _ulReserved2_msg字段标识标头部后面的消息类型,_status字段包含所请求操作的状态并由服务器填充,_ulChecksum包含从_ulReserved2字段后面开始的消息的校验和。跟本漏洞相关的是CPMCreateQueryIn消息,故本文暂且重点关注该消息。 此消息创建一个新的搜索查询,并具有以下结构:[table][tr][td]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18[/td][td]
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具有以下结构:[table][tr][td]
1
2
3
4
5
6[/td][td]
Offset Size(bytes) Field
-------------------------------------------
0x00 0x1 count
0x01 0x1 isPresent
0x02 0x3 padding
0x05 var RestrictionisPresent字段标识Restriction字段是否存在且Restriction字段是否包含CRestriction结构。 CRestriction在查询命令树中包含限制节点,并具有以下格式:[table][tr][td]
1
2
3
4
5[/td][td]
Offset Size(bytes) Field
------------------------------------------
0x00 0x4 ulType
0x04 0x4 Weight
0x08 var RestrictionulType标识Restriction字段中存在的限制结构的类型。 此漏洞涉及具有指定CPropertyRestriction的ulType为RTProperty(0x5)的CRestrictions。 某些CRestriction类型可以包含嵌套的CRestrictions,形成一个限制树; 因此,CPropertyRestriction可以嵌入以下任何限制中:
- RTAnd (0x1), Restriction contains a CNodeRestriction structure
- RTOr (0x2), Restriction contains a CNodeRestriction structure
- RTNot (0x3), Restriction contains a CRestriction structure
- RTProximity (0x6), Restriction contains a CNodeRestriction 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 structureRTPhrase (0x00FFFFFD), Restriction contains a CNodeRestriction structure
上述列表中的限制具有以下结构:[table][tr][td]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19[/td][td]
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结构包含从每一行获取的属性,比较运算符和常量。 对于每一行,将行中特定属性返回的值与常量进行比较,以确定它是否具有指定的关系。 此限制具有以下结构:[table][tr][td]
1
2
3
4
5
6
7[/td][td]
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 lcidrelop字段标识比较的类型,例如, 大于,小于,正则表达式等。属性字段标识要匹配的属性,而prval字段指定与属性相关的值。 prval字段包含一个CBaseStorageVariant项,它具有以下结构:[table][tr][td]
1
2
3
4
5
6[/td][td]
Offset Size (bytes) Field
------------------------------------------
0x00 0x2 vType
0x02 0x1 vData1
0x03 0x1 vData2
0x04 var vValuevType字段标识存储在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字节顺序存储漏洞触发代码[table][tr][td]
1[/td][td]
使用的dll版本为7.0.7601.23861CPropertyRestriction::CPropertyRestriction(long, class PDeSerStream &):[table][tr][td]
1
2
3
4
5
6
7[/td][td]
.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 ):[table][tr][td]
1
2
3
4
5
6
7
8
9
10
11
12
13
14[/td][td]
.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):[table][tr][td]
1
2
3
4
5
6
7
8
9
10
11[/td][td]
.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(), 不检测类型就直接解析vValueCNFA::CNFA(unsigned __int16 *, int, int):[table][tr][td]
1
2
3
4
5[/td][td]
.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漏洞触发流<ul type="1" class="litype_1">The attacker sends a NEGOTIATE request to the target server:
[ Attacker ] --------------------> [ Target ]The server responds:
[ Attacker ] [ Target ]The server responds:
[ Attacker ] [ Target ]The server responds:
[ Attacker ] [ Target ]The server responds:
[ Attacker ] [ Target ]The server responds:
[ Attacker ] [ Target ]The server responds with a CPMConnectOut message:
[ Attacker ] [ Target ]The server responds with a CPMCreateQueryOut message:
[ Attacker ] |
|