标题 简介 类型 公开时间
关联规则 关联知识 关联工具 关联文档 关联抓包
参考1(官网)
参考2
参考3
详情
[SAFE-ID: JIWO-2022-3125]   作者: 大猪 发表于: [2022-06-19]

本文共 [6] 位读者顶过

In this excerpt of a Trend Micro Vulnerability Research Service vulnerability report, Guy Lederfein and Jason McFadyen of the Trend Micro Research Team detail a recently patched code execution vulnerability in the Microsoft Windows operating system. The bug was originally discovered and reported to Microsoft by Yuki Chen. A stack buffer overflow vulnerability exists in Windows Network File System. A remote attacker can exploit this vulnerability by sending specially crafted RPC packets to a server, resulting in code execution in the context of SYSTEM. The following is a portion of their write-up covering CVE-2022-26937, with a few minimal modifications. [出自:jiwo.org]


A stack buffer overflow vulnerability exists in Windows Network File System. The vulnerability is due to improper handling of crafted RPC responses to Portmap requests made by the Network Lock Manager (NLM) RPC program.

A remote attacker can exploit this vulnerability by sending malicious RPC calls to a target server. Successful exploitation may result in arbitrary code execution under the context of SYSTEM. Unsuccessful exploitation results in a crash of the target system.

The Vulnerability

Microsoft Windows ships with several network features designed to communicate and interact with non-Windows files shares. One of these modules is called Network File System (NFS).

NFS is a network file system protocol originally developed by Sun Microsystems in 1984. Version 2 is documented in RFC 1094. Version 3 is documented in RFC 1813. Version 4 was developed by the IETF and is documented in RFC 3010 (released December 2000) and revised in RFC 3530 (released April 2003) and RFC 7530 (released March 2015). NFS allows users to access remote file shares in the same way that the local file system is accessed. Different access levels and permissions can be set on the share, such as read-write and read-only. Additionally, IP/UID/GID/Kerberos security can be used. NFS uses Open Network Computing (ONC) Remote Procedure Call (RPC) to exchange control messages. ONC RPC was originally developed by Sun Microsystems and can also be referred to as Sun RPC.

The Network Lock Manager (NLM) protocol is an extension of NFS versions 2 and 3, which provides a System V style of advisory file and record locking over the network. Since NFS versions 2 and 3 are stateless protocols, the NLM protocol was developed to manage the state of locks on files stored on NFS shares. The NLM protocol supports both synchronous and asynchronous procedures to implement locking and file-sharing functionality. Similar to NFS, NLM also uses ONC RPC to exchange control messages.

ONC RPC uses XDR packets, which can be transmitted over UDP or TCP. Over UDP, the XDR packet is contained within the UDP payload. Over TCP, XDR packets are preceded by a Fragment header (as illustrated in the following table). The most significant bit of the Fragment header indicates whether the packet is the last fragment, and the remaining 31 bits are the length of the Fragment that follows. The Fragment itself contains the XDR packet.

Offset Size Description
(bytes)
------- ------- ----------------------------------
0x00 4 Fragment header, the highest bit is the last fragment flag,
lower bits represent the fragment size = N
0x04 N RPC Message

The structure of an ONC RPC call is as follows:

Offset Size Description
(bytes)
------- ----- ----------------------------------
0x00 4 XID
0x04 4 Message Type (Call: 0)
0x08 4 RPC Version
0x0C 4 Program (e.g., 100000: portmap)
0x10 4 Program Version
0x14 4 Procedure
0x18 4 Credentials Flavour (e.g., AUTH_UNIX: 1)
0x1c 4 Credentials Length (q)
0x20 q Credentials
0x20+q 4 Verifier Flavour (e.g., AUTH_NULL: 0)
0x24+q 4 Verifier Length: w
0x28+q w Verifier
0x28+q+w N Program-specific data

The Program field of the RPC message specifies what RPC service the message is sent to. Windows NFS server implements the NLM protocol via RPC with Program type set to 100021. It supports multiple RPC procedures, which can be specified in the Procedure field in the RPC message. A list of synchronous and asynchronous procedures supported by the NLM protocol version 3 follows:

Procedure Name Caller Synchronous/Asynchronous
--------- -------------- ----- --------------------
0 NLM_NULL Client Synchronous
1 NLM_TEST Client Synchronous
2 NLM_LOCK Client Synchronous
3 NLM_CANCEL Client Synchronous
4 NLM_UNLOCK Client Synchronous
5 NLM_GRANTED Server Synchronous
6 NLM_TEST_MSG Client Asynchronous
7 NLM_LOCK_MSG Client Asynchronous
8 NLM_CANCEL_MSG Client Asynchronous
9 NLM_UNLOCK_MSG Client Asynchronous
10 NLM_GRANTED_MSG Server Asynchronous
11 NLM_TEST_RES Server Asynchronous
12 NLM_LOCK_RES Server Asynchronous
13 NLM_CANCEL_RES Server Asynchronous
14 NLM_UNLOCK_RES Server Asynchronous
15 NLM_GRANTED_RES Client Asynchronous
20 NLM_SHARE Client Synchronous
21 NLM_UNSHARE Client Synchronous
22 NLM_NM_LOCK Client Synchronous
23 NLM_FREE_ALL Client Synchronous

Microsoft Windows runs the RPCBIND RPC program, which implements the Port Mapper protocol, documented in RFC 1833. The RPCBIND program converts RPC program numbers into universal addresses, which can then be used by programs to communicate over UDP or TCP. Briefly, the way it works is that when a program wishes to use RPC, it registers its ports with the host's Port Mapper. A client that wishes to issue RPC calls connects to the Port Mapper, uses various RPC calls such as GETPORT, GETADDR etc. to obtain a port on which the RPC service is available, and connects to the desired RPC service. Standard RPC program numbers have been defined and maintained by IANA and they include portmapper (100000), nfs (100003), mount daemon (100005) and hundreds of other less commonly used programs. Only the portmapper service and NFS service have standard ports of 111 and 2049 respectively.

Windows implements the RPCBIND protocol via RPC with Program type set to 100000. It supports multiple RPC procedures, which can be specified in the Procedure field in the RPC message. One of the procedures supported by the RPCBIND program when Program Version is set to 3 or 4, is GETADDR, which is procedure number 3. The reply to this RPC call contains the Universal Address associated with the callee. The format for the returned Universal Address is XDR_String, which has the following format:

Offset Size Description
(bytes)
------- ----- ----------------------------------
0x00 4 String Length (X)
0x04 X String Value

A stack buffer overflow vulnerability exists in Windows Network File System. More specifically, the vulnerability is due to incorrect handling of the Universal Address field returned in GETADDR RPC replies. When Windows NFS responds to an NLM call in an asynchronous manner, the NlmGetClientAddressAndConnection() function is called. This flow is triggered either as a response to an asynchronous NLM call, such as NLM_TEST_MSG, NLM_LOCK_MSG, NLM_UNLOCK_MSG, or when the server sends an `NLM_GRANTED` call to the client, after a previous (synchronous or asynchronous) call by the client to create a lock returned the status `LCK_BLOCKED`. If the IPv6 protocol is used for communication over the ONC RPC protocol, the server will issue a GETADDR RPC call to the client to retrieve its IP address. When the Universal Address field returned by the client in the GETADDR reply is processed by the NFS server, the field is copied using memmove() into a buffer of size 96 bytes. In addition, this buffer is later referenced at an index equal to the Universal Address field’s string size and set to 0. However, the NlmGetClientAddressAndConnection() function does not verify the size of the returned Universal Address string. Therefore, if the string provided by the client is 96 bytes or longer, the buffer will be written past its boundary, resulting in the stack buffer overflow condition.

A remote attacker can exploit this vulnerability by sending an NLM request triggering an asynchronous response by the NFS server. When the server sends a GETADDR RPC request, the attacker can respond with a crafted GETADDR reply. Successful exploitation may result in arbitrary code execution under the context of SYSTEM. Unsuccessful exploitation results in a crash of the target system.

Source Code Walkthrough

The following code snippet was taken from nfssvr.sys version 10.0.17763.1999. Comments added by Trend Micro have been highlighted.

 In function NlmGetClientAddressAndConnection():

.text:00000001C00CC1B2 loc_1C00CC1B2:
.text:00000001C00CC1B2 mov rdx, [rsp+1B0h+var_160]
.text:00000001C00CC1B7 lea rax, [rsp+1B0h+var_158]
.text:00000001C00CC1BC mov rcx, [rsp+1B0h+var_148]
.text:00000001C00CC1C1 mov r9d, 7530h
.text:00000001C00CC1C7 mov r8, r12
.text:00000001C00CC1CA mov [rsp+1B0h+Timeout], rax
.text:00000001C00CC1CF call cs:__imp_OncRpcSendCallWaitReply ; Server sends GETADDR call
.text:00000001C00CC1D6 nop dword ptr [rax+rax+00h]
.text:00000001C00CC1DB mov r14d, eax
[... Truncated for readability ...]
.text:00000001C00CC21B loc_1C00CC21B:
.text:00000001C00CC21B mov rbx, [rbp+0B0h+var_108]
.text:00000001C00CC21F xor r12d, r12d
.text:00000001C00CC222 test r14d, r14d ; Verify RPC call succeeded
.text:00000001C00CC225 js loc_1C00CC441
.text:00000001C00CC22B movzx edi, [rsp+1B0h+var_170]
.text:00000001C00CC230 mov r9, [rsp+1B0h+var_158]
.text:00000001C00CC235 cmp di, si ; Check if using AF_INET (IPv4)
.text:00000001C00CC238 jnz short loc_1C00CC2A1
[... Truncated for readability ...]
.text:00000001C00CC2A1 loc_1C00CC2A1:
.text:00000001C00CC2A1 mov eax, 60h ; '`'
.text:00000001C00CC2A6 mov [rbp+0B0h+var_DE], ax
.text:00000001C00CC2AA lea rax, [rbp+0B0h+var_B0]
.text:00000001C00CC2AE mov [rbp+0B0h+var_D8], rax
.text:00000001C00CC2B2 cmp [r9+108h], r12d
.text:00000001C00CC2B9 jl short loc_1C00CC301
.text:00000001C00CC2BB mov rcx, [r9+48h]
.text:00000001C00CC2BF test rcx, rcx
.text:00000001C00CC2C2 jz short loc_1C00CC301
.text:00000001C00CC2C4 mov edx, [rcx+40h]
.text:00000001C00CC2C7 sub edx, [rcx+38h]
.text:00000001C00CC2CA mov r10d, [rcx+4Ch]
.text:00000001C00CC2CE cmp r10d, edx
.text:00000001C00CC2D1 jb short loc_1C00CC2DB
.text:00000001C00CC2D3 mov r8d, r10d
.text:00000001C00CC2D6 sub r8d, edx
.text:00000001C00CC2D9 jmp short loc_1C00CC2DE
.text:00000001C00CC2DB ; ---------------------------------------------------------------------------
.text:00000001C00CC2DB
.text:00000001C00CC2DB loc_1C00CC2DB:
.text:00000001C00CC2DB mov r8d, r15d
.text:00000001C00CC2DE
.text:00000001C00CC2DE loc_1C00CC2DE:
.text:00000001C00CC2DE cmp r10d, edx
.text:00000001C00CC2E1 mov eax, r12d
.text:00000001C00CC2E4 cmovnb eax, r8d
.text:00000001C00CC2E8 cmp eax, 4
.text:00000001C00CC2EB jb short loc_1C00CC301
.text:00000001C00CC2ED mov rax, [rcx+40h]
.text:00000001C00CC2F1 mov edx, [rax]
.text:00000001C00CC2F3 add rax, 4
.text:00000001C00CC2F7 bswap edx
.text:00000001C00CC2F9 mov [rcx+40h], rax
.text:00000001C00CC2FD mov eax, edx ; eax has the Universal Address string length
.text:00000001C00CC2FF jmp short loc_1C00CC30C
.text:00000001C00CC301 ; ---------------------------------------------------------------------------
.text:00000001C00CC301
.text:00000001C00CC301 loc_1C00CC301:
.text:00000001C00CC301 mov rcx, r9
.text:00000001C00CC304 call XdrDecodeIntSlow
.text:00000001C00CC309 movzx edx, ax
.text:00000001C00CC30C
.text:00000001C00CC30C loc_1C00CC30C:
.text:00000001C00CC30C mov rdi, [rsp+1B0h+var_158]
.text:00000001C00CC311 mov [rbp+0B0h+var_E0], dx
.text:00000001C00CC315 movzx esi, ax ; move string length to esi
.text:00000001C00CC318 cmp [rdi+108h], r12d
.text:00000001C00CC31F jl loc_1C00CC3AA
.text:00000001C00CC325 mov rcx, [rdi+48h]
.text:00000001C00CC329 test rcx, rcx
.text:00000001C00CC32C jnz short loc_1C00CC333
.text:00000001C00CC32E mov eax, r12d
.text:00000001C00CC331 jmp short loc_1C00CC357
[... Truncated for readability ...]
.text:00000001C00CC357 loc_1C00CC357:
.text:00000001C00CC357 cmp eax, esi
.text:00000001C00CC359 jb short loc_1C00CC3AA
.text:00000001C00CC35B mov rdx, r12
.text:00000001C00CC35E test rcx, rcx
.text:00000001C00CC361 jz short loc_1C00CC367
.text:00000001C00CC363 mov rdx, [rcx+40h] ; Src
.text:00000001C00CC367
.text:00000001C00CC367 loc_1C00CC367:
.text:00000001C00CC367 mov r8, rsi ; string length used as size of memmove
.text:00000001C00CC36A lea rcx, [rbp+0B0h+var_B0] ; void *
.text:00000001C00CC36E call memmove ; buffer overflow triggered for string length > 96
.text:00000001C00CC373 mov rax, [rdi+48h]
.text:00000001C00CC377 add [rax+40h], rsi
.text:00000001C00CC37B mov rcx, [rdi+48h]
.text:00000001C00CC37F test rcx, rcx
.text:00000001C00CC382 jnz short loc_1C00CC390
.text:00000001C00CC384 mov r8, [rcx+40h]
.text:00000001C00CC388 mov rax, r12
.text:00000001C00CC38B mov rdx, r12
.text:00000001C00CC38E jmp short loc_1C00CC39B
.text:00000001C00CC390 ; ---------------------------------------------------------------------------
.text:00000001C00CC390
.text:00000001C00CC390 loc_1C00CC390:
.text:00000001C00CC390 mov rdx, [rcx+40h]
.text:00000001C00CC394 mov rax, [rcx+38h]
.text:00000001C00CC398 mov r8, rdx
.text:00000001C00CC39B
.text:00000001C00CC39B loc_1C00CC39B:
.text:00000001C00CC39B sub rax, rdx
.text:00000001C00CC39E and eax, 3
.text:00000001C00CC3A1 add rax, r8
.text:00000001C00CC3A4 mov [rcx+40h], rax
.text:00000001C00CC3A8 jmp short loc_1C00CC3B8
.text:00000001C00CC3AA ; ---------------------------------------------------------------------------
.text:00000001C00CC3AA
.text:00000001C00CC3AA loc_1C00CC3AA:
.text:00000001C00CC3AA
.text:00000001C00CC3AA lea r8, [rbp+0B0h+var_B0]
.text:00000001C00CC3AE mov edx, esi
.text:00000001C00CC3B0 mov rcx, rdi
.text:00000001C00CC3B3 call XdrDecodeOpaqueSlow
.text:00000001C00CC3B8
.text:00000001C00CC3B8 loc_1C00CC3B8:
.text:00000001C00CC3B8 movzx edi, [rsp+1B0h+var_170]
.text:00000001C00CC3BD mov [rbp+rsi+0B0h+var_B0], r12b ; buffer overflow triggered
; for string length == 96
.text:00000001C00CC3C2 mov esi, 2

Detecting Attacks

ONC RPC uses XDR packets, which can be transmitted over UDP or TCP. Over UDP, the XDR packet is contained within the UDP payload. Over TCP, XDR packets are preceded by a Fragment header (as illustrated in the following table). The most significant bit of the Fragment header indicates whether the packet is the last fragment, and the remaining 31 bits are the length of the Fragment that follows. The Fragment itself contains the XDR packet.

Offset Size Description
(bytes)
------- ------ ----------------------------------
0x00 4 Fragment header, the highest bit is the last fragment flag,
lower bits represent the fragment size = N
0x04 N RPC Message

The detection device must inspect all outgoing ONC RPC calls, which have the following structure:

Offset Size Description
(bytes)
------- ----- ----------------------------------
0x00 4 XID
0x04 4 Message Type (Call: 0)
0x08 4 RPC Version
0x0C 4 Program (e.g., 100000: portmap)
0x10 4 Program Version
0x14 4 Procedure
0x18 4 Credentials Flavour (e.g., AUTH_UNIX: 1)
0x1c 4 Credentials Length (q)
0x20 q Credentials
0x20+q 4 Verifier Flavour (e.g., AUTH_NULL: 0)
0x24+q 4 Verifier Length: w
0x28+q w Verifier
0x28+q+w N Program-specific data

The detection device must check if the Message Type field is 0 (Call), the Program field is 100000 (portmap), the Program Version field is larger than 2, and the Procedure field is equal to 3 (GETADDR). If found, the device must inspect the Program-specific data object. This object uses the rpcb structure, which has the following format:

Offset Size Description
(bytes)
------- ----- ----------------------------------
0x00 4 Program Number
0x04 4 Version Number
0x08 4 Network ID Length (X1)
0x0C X1 Network ID
0x0C+X1 4 Universal Address Length (X2)
0x10+X1 X2 Universal Address
0x10+X1+X2 4 Owner Length (X3)
0x14+X1+X2 X3 Owner

If the Program Number field is set to 100021 (NLM), the detection device must inspect all incoming ONC RPC replies, which have the following structure:

Offset Size Description
(bytes)
------- ----- ----------------------------------
0x00 4 XID
0x04 4 Message Type (Reply: 1)
0x08 4 Reply State (e.g., accepted: 0)
0x0c 4 Verifier Flavour (e.g., AUTH_NULL: 0)
0x10 4 Verifier Length: w
0x14 w Verifier
0x14+w 4 Accept State (e.g., SUCCESS: 0)
0x18+w N Program-specific data

The detection device must check if the XID field is equal to the XID field of the GETADDR RPC call detected, and the Message Type field is 1 (Reply). If found, the device must inspect the Program-specific data object. This object uses the XDR_String structure, which has the following format:

Offset Size Description
(bytes)
------- ----- ----------------------------------
0x00 4 String Length (X)
0x04 X String Value

If the String Length field is larger than 95, the traffic should be considered suspicious; an attack exploiting this vulnerability is likely underway.

Conclusion

This bug was patched by Microsoft in May 2022 and assigned CVE-2022-26937. In their write-up, they also list disabling NFSV2 and NFSV3 as a method to mitigate attacks. However, this could lead to a loss of functionality. Applying the security update is the best method to fully address this vulnerability.

Special thanks to Guy Lederfein and Jason McFadyen of the Trend Micro Research Team for providing such a thorough analysis of this vulnerability. For an overview of Trend Micro Research services please visit http://go.trendmicro.com/tis/.

The threat research team will be back with other great vulnerability analysis reports in the future. Until then, follow the ZDI team for the latest in exploit techniques and security patches.

评论

暂无
发表评论
 返回顶部 
热度(6)
 关注微信