This article is a highlight from the Kanxue Forum.
Author from Kanxue ForumID: Toxic
-
Table of Contents
-
1. Vulnerability Information
-
1.1 Brief Description
-
1.2 Component Overview
-
1.3 Exploitation
-
1.4 Impact
-
1.5 Solutions
-
2. Vulnerability Reproduction
-
2.1 Environment Setup
-
2.2 Reproduction Process
-
3. Vulnerability Analysis
-
3.1 Basic Information
-
3.2 Background Knowledge
-
3.2.1 Basic Knowledge
-
3.2.2 Terminology
-
3.3 Detailed Analysis
-
3.3.1 Basic Analysis
-
(1) Neighbor Discovery Extension
-
(2) RDNSS Option Structure
-
(3) Procedure in IPv6 Hosts
-
(4) Crash Analysis
-
3.3.2 Static Analysis
-
(1) Function Call Chain
-
(2) Vulnerable Function Analysis
-
3.3.3 Dynamic Analysis
-
4. Exploitation Ideas
-
4.1 Exploitation Conditions
-
4.2 Exploitation Process
-
4.3 Attack Vectors
-
5. Traffic Analysis
-
4. Mitigation Measures
-
5. References
1. Vulnerability Information
1.1 Brief Description
Vulnerability Name: Windows TCP/IP Remote Code Execution Vulnerability
Vulnerability ID: CVE-2020-16898
Vulnerability Type: Design Weakness
Exploitation Difficulty: Medium
Base Privileges: None required
1.2 Component Overview
TCP/IP is the communication protocol used on the Internet. In earlier versions of Windows, TCP/IP was a separate optional component that could be added or removed like any other protocol.
Starting from Windows XP/Server 2003, TCP/IP became a core component of the operating system and could not be removed. Making TCP/IP a core component of Windows is very meaningful, as its functionality is especially important for network operations and Active Directory domain environments on Microsoft Windows Server. The entire Active Directory architecture is based on the DNS hierarchy and relies on the TCP/IP transport protocol.
The TCP/IP functionality in Microsoft Windows operates at the kernel level and is provided by the driver tcpip.sys. This driver handles all incoming and outgoing TCP/IP communication information, including parsing the data packets received from the network interface and interpreting this data to pass it to higher-level components.
1.3 Exploitation
This vulnerability primarily arises from a flaw in the Windows TCP/IP stack when processing ICMPv6 router advertisement packets with option type 25 (0x19, Recursive DNS Server Option) and an even length field value, leading to a remote code execution vulnerability. Attackers who successfully exploit this vulnerability can execute arbitrary code on the target machine (host or server).
1.4 Impact
Microsoft Windows 10 1709Microsoft Windows 10 1803Microsoft Windows 10 1809Microsoft Windows 10 1903Microsoft Windows 10 1909Microsoft Windows 10 2004Microsoft Windows Server 2019Microsoft Windows Server, version 1903Microsoft Windows Server, version 1909Microsoft Windows Server, version 2004
1.5 Solutions
Microsoft has released a security update patch for this vulnerability, available at:
https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-16898
2. Vulnerability Reproduction
2.1 Environment Setup
Target Machine: Windows 10 1809 x64
Target Machine Operation: No operation required, just ensure normal communication with the attacking machine.
2.2 Reproduction Process
2.1 Obtain the target host’s IPv6 address and MAC address through various means (specific methods can be explored independently, relatively simple).
2.2 Attack machine runs poc with python3:

2.3 Target machine crashes:

3. Vulnerability Analysis
3.1 Basic Information
Vulnerable File: tcpip.sys
Vulnerable Function: Ipv6pUpdateRDNSS()
Vulnerable Object: Option structure in ICMPv6 router broadcasts
3.2 Background Knowledge
(Due to space constraints, a detailed introduction to IPv6 router broadcasts used for DNS configuration will not be provided here; more detailed information can refer toRFC8106).
3.2.1 Basic Knowledge
IPv6 Router Advertisement (RA) options, also known as DNS RA options, allow IPv6 routers to broadcast a list of DNS Recursive Server Addresses (RDNSS) and DNS Search Lists (DNSSL) to IPv6 hosts, primarily used for DNS name resolution and domain suffix handling on IPv6 hosts.
IPv6 Neighbor Discovery (ND) and IPv6 Stateless Address Autoconfiguration (SLAAC) provide a method for configuring fixed or mobile nodes using one or more IPv6 addresses, default routers, and some other parameters.
When roaming hosts connect to another network, manual configuration is not possible. Although static configuration is possible, it is generally not recommended for generic hosts such as laptops. For example, if a host runs its own recursive name server directly connected to the global DNS, then the locally defined namespace becomes unavailable to the host.
Accessing DNS is a fundamental requirement for almost all hosts, so IPv6 SLAAC cannot be deployed as an alternative model in any real network environment without any DNS configuration support.
For DNS servers in IPv4 environments, these issues are easily resolved. However, for IPv6 network environments, these issues become more complicated. Therefore, RFC8106 defines a mechanism based on DNS RA options to allow IPv6 hosts to perform automatic DNS configuration.
In networks where IPv6 hosts are automatically configured through SLAAC without a DHCPv6 infrastructure or some hosts lack a DHCPv6 client, RA-based DNS configuration can be used as an alternative. However, networks that require distributing other information may still use DHCPv6. In these networks, RA-based DNS configuration may not be needed.
RA-based DNS configuration allows IPv6 hosts to acquire DNS configuration (i.e., RDNSS and DNSSL) for the link to which they are connected. Additionally, hosts learn this DNS configuration from the same RA message that provides link configuration information.
3.2.2 Terminology
Recursive DNS Server (RDNSS): A server that provides recursive DNS resolution services to convert domain names into IP addresses or resolve PTR records defined in RFC1034 and RFC1035.
RDNSS Option: An IPv6 RA option used to transmit RDNSS information to IPv6 hosts【RFC4861】.
DNS Search List (DNSSL): A list of DNS suffix domain names used by IPv6 hosts when performing DNS query searches for short unqualified domain names.
DNSSL Option: An IPv6 RA option used to pass DNSSL information to IPv6 hosts.
3.3 Detailed Analysis
3.3.1 Basic Analysis
RFC8106 standardizes the RDNSS option, which includes addresses of RDNSSes. This information uses existing ND messages (e.g., RA) as a carrier. IPv6 hosts can configure one or more IPv6 addresses of RDNSS through RA messages.
(1) Neighbor Discovery Extension
The IPv6 DNS configuration algorithm used in neighbor discovery defined in RFC8106 requires two ND options: RDNSS option and DNSSL option. The RDNSS option is related to this vulnerability, while the other one is related to CVE-2020-16899.
(2) RDNSS Option Structure
The overall structure of the RDNSS option is as follows:

For the Length field, if the option contains only one IPv6 address, the minimum value is 3. For each additional RDNSS address, the length increases by 2. The receiving host uses this field to determine the number of IPv6 addresses in the option.
(3) Procedure in IPv6 Hosts
When a host receives DNS options in an RA message, the processing procedure is as follows:
1. First, check the legality of the Length field: whether it is greater than or equal to the minimum value of 3 and whether it satisfies (Length – 1) % 2 == 0;
2. For the RDNSS option, check whether the Address field is a unicast address;
3. If the above validations pass, the host should sequentially copy the values of the options into the DNS repository and resolver repository. Otherwise, the host must discard these options.
(4) Crash Analysis
First, analyze the dmp file to check the crash site:
No obvious valuable Call Stack information was found, but it was discovered that the final crash reason was a GS mechanism Security Cookie check failure, meaning this value was overwritten. Thus, it is likely a buffer overflow.
In addition, only the function tcpip!Ipv6pHandleRouterAdvertisement+0x1269 was found, and afterwards, it directly reported a gsfailure.
3.3.2 Static Analysis
The analyzed file is the tcpip.sys file of Windows 10 1809 x64, version 10.0.17763.316.
(1) Function Call Chain
Based on the crash site information, the key function tcpip!Ipv6pHandleRouterAdvertisement() was obtained, and the call chain before and after the vulnerable function was confirmed.
First, check its cross-reference relationship:
The upper calling function is Icmpv6ReceiveDatagrams(), follow up and check the cross-reference relationship:
No explicit function calls were found. Turn to search the lower layers of tcpip!Ipv6pHandleRouterAdvertisement():
The vulnerable function call was discovered. Thus, the function call chain can be simply summarized as:
Icmpv6ReceiveDatagrams() -> tcpip!Ipv6pHandleRouterAdvertisement() -> Ipv6pUpdateRDNSS()
(2) Vulnerable Function Analysis
After a brief analysis, it can be confirmed that the top-level function Icmpv6ReceiveDatagrams() does not contain substantial code related to this vulnerability, while the function tcpip!Ipv6pHandleRouterAdvertisement() calls the vulnerable function Ipv6pUpdateRDNSS().
Based on the crash analysis, it ultimately reported a gsfailure, and the key function was tcpip!Ipv6pHandleRouterAdvertisement(). GS verification was indeed found at the starting position of this function:
Thus, it is likely that a buffer overflow occurred, causing the GS verification of the function tcpip!Ipv6pHandleRouterAdvertisement() to fail.
Enter the vulnerable function Ipv6pUpdateRDNSS():
The declaration of the NdisGetDataBuffer() function is as follows:
PVOID NdisGetDataBuffer( PNET_BUFFER NetBuffer, // [in], a pointer to a NetBuffer structure ULONG BytesNeeded, // [in], the number of contiguous bytes of data requested PVOID Storage, // [in, optional], a pointer to a buffer, or NULL if no buffer is provided by the caller UINT AlignMultiple, // [in], the alignment multiple expressed in power of two. For example, 2, 4, 8, 16, and so forth. If AlignMultiple is 1, then there is no alignment requirement. UINT AlignOffset // [in], the offset, in bytes, from the alignment multiple.); // Return ValueA pointer to the start of the contiguous data or NULL.
If the value of the DataLength field in the NET_BUFFER_DATA part of the NET_BUFFER structure pointed to by the NetBuffer parameter is less than the value of the BytesNeeded parameter, the function returns NULL. The structure of NET_BUFFER is as follows:
typedef struct _NET_BUFFER { union { struct { PNET_BUFFER Next; PMDL CurrentMdl; ULONG CurrentMdlOffset; union { ULONG DataLength; SIZE_T stDataLength; }; PMDL MdlChain; ULONG DataOffset; }; SLIST_HEADER Link; NET_BUFFER_HEADER NetBufferHeader; }; USHORT ChecksumBias; USHORT Reserved; NDIS_HANDLE NdisPoolHandle; PVOID NdisReserved[2]; PVOID ProtocolReserved[6]; PVOID MiniportReserved[4]; NDIS_PHYSICAL_ADDRESS DataPhysicalAddress; union { PNET_BUFFER_SHARED_MEMORY SharedMemoryInfo; PSCATTER_GATHER_LIST ScatterGatherList; };} NET_BUFFER, *PNET_BUFFER;
First, obtain the RDNSS option structure, then read the Length field to calculate how many Address values there are.
After confirming how many Addresses there are, enter a loop to process each Address. Here, there is also a judgment: if it is not a unicast address, it is ignored:
In the processing above, there is a problem: assuming the length is 4, then after the calculation, the value of AddressCount should be 1.
At this point, under normal logic, the Ipv6pUpdateRDNSS() function should allocate a buffer of 32 bytes (4*8), but subsequently only 24 bytes were allocated: sizeof(ND_OPTION_RDNSS) + sizeof(IN6_ADDR) = 8 + 16 = 24, leading to a buffer overflow.
According to RFC8106 standards, the value of the Length field should satisfy the minimum of 3 odd values. When providing an even Length value, the Windows TCP/IP stack incorrectly advanced the buffer by 8 bytes.
This is mainly because the stack internally counts in 16-byte increments and does not use handling code for non-RFC compatible length values. This mismatch caused the stack to interpret the last 8 bytes of the current option as the start of the second option, ultimately leading to a buffer overflow and potential RCE.
3.3.3 Dynamic Analysis
First, in the pv6pHandleRouterAdvertisement() function, the NdisGetDataBuffer() function is called for the first time to access data (contiguous or non-contiguous) from the _NET_BUFFER structure, using the CurrentMdlOffset field in the _NET_BUFFER structure to locate the starting address of the data to be accessed relative to the MDL pointing to memory data:
The second call to the NdisGetDataBuffer() function retrieves the RDNSS Option:
Arriving at the Ipv6pUpdateRDNSS() function call, at this point, rdx contains the _NET_BUFFER:
First, use the NdisGetDataBuffer() function to read the Option structure:
Then call the NetioAdvanceNetBuffer() function, after execution, the partial data of _NET_BUFFER is as follows:
Continuing down, begin calculating AddressCount, using the formula (Length – 1) / 2:
The final calculation result is 1.
Next, check whether the LifeTime field is set to the maximum value 0xffffffff:
Continuing down, since AddressCount = 1, the next call to NdisGetDataBuffer occurs:
The parameter situation at this time is as follows:
Previously, 8 bytes of data were read, while this time 16 bytes are read, and at this time, it returns the address of the first Recursive DNS Server value:
Then check whether the contents of the address 0xffffe40b85d8afb8 are a unicast address:
Continuing down, arrive at the Ipv6pCreateRDNSSEntry() function call, with the following parameter situation:
First, call ExAllocatePoolWithTag() and memset() for memory allocation and initialization:
After some processing, the final result is as follows:
Subsequently, when performing the security cookie check, the check passes, and the function returns:
Back in the Ipv6pHandleRouterAdvertisement() function, during the next data read, the offset becomes 0x28, pointing to the second Recursive DNS Server:
This processing flow is processed according to Type 0x18. The processing logic for Type 0x18 is as follows:
Directly call the NdisGetDataBuffer() function; since the data is non-contiguous and the Storage parameter (r8) is specified as an address on the stack, a large amount of data will be copied to the stack, thereby corrupting normal stack data:
In the above image, the loop calls the memcpy() function to copy data to the stack, causing stack corruption. The final result on the stack is as follows:
Ultimately, when the Ipv6pHandleRouterAdvertisement() function returns, the cookie check fails, causing a crash.
4. Exploitation Ideas
4.1 Exploitation Conditions
The attacker needs to obtain the target’s IPv6 and MAC addresses.
The attacker needs to combine with other memory leak or information leak vulnerabilities to achieve RCE.
The attacker needs to find a way to bypass the GS protection mechanism of tcpip.sys.
4.2 Exploitation Process
The attacker directly sends specially crafted ICMPv6 router advertisement packets to the target:
[ Attacker ] <--------------------> [ Target ]
4.3 Attack Vectors
After establishing a connection, the attacker can directly send attack packets using IPv6.
5. Traffic Analysis
Since this vulnerability directly involves IPv6, some firewall solutions deployed above the IP layer cannot detect traffic for this vulnerability. However, firewalls with IP layer traffic detection can easily detect malicious traffic:

In the traffic, it can be clearly seen that the Address field of the first Option structure is incorrectly identified and calculated as a value of a Recursive DNS Server:
The address of the first Recursive DNS Server is 0018-0027, and the subsequent 8 bytes should not be recognized again. When selecting the second Recursive DNS Server, the situation is as follows:

The address of the second Recursive DNS Server is 0028-0037. However, the last 8 bytes in this 16-byte segment are clearly the content of the next ICMPv6 Option structure:

Administrators can start PowerShell or cmd and enter the following command to check the list of all network IPv6 interfaces and their corresponding index numbers:
Sample output as follows:
Confirm the RDNSS functionality status of the network interface:
netsh int ipv6 sh int Idx number

Execute the following command to disable the RDNSS functionality (replace Idx number with the index value of the network interface to be disabled):
netsh int ipv6 set int Idx number rabaseddnsconfig=disable
Sample output as follows:
At this point, confirm again the RDNSS functionality status of the interface; the RDNSS functionality has been disabled:

1. https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-16898
2. https://tools.ietf.org/html/rfc8106
3. https://www.mcafee.com/blogs/other-blogs/mcafee-labs/cve-2020-16898-bad-neighbor/

Kanxue ID: Toxic
https://bbs.pediy.com/user-home-779730.htm
* This article is original by Toxic from Kanxue Forum, please indicate the source from Kanxue Community when reprinting.
Good news!! NowKanxue “Advanced Android Training Course” offline class & online course (December class) is open for enrollment! Friends who have not enrolled in the advanced class before should hurry up to grab the opportunity to sign up, promotion and salary increase are within reach!!

* Windows Memory II: The Evolution of x64 Kernel Memory Layout
* Linux kernel pwn: ROP & ret2usr
* An idea for modifying kernel non-page write-protected memory without CR0 or MDL (x64)
* A function extraction shell sample of a custom classloader
* RC4, Base64 modification Kanxue CTF – Transformers Learning Notes
Public Account ID: ikanxue
Official Weibo: Kanxue Security