Analysis of Windows TCP/IP Remote Code Execution Vulnerability (CVE-2020-16898)

CVE Number
CVE-2020-16898
Vendor
Microsoft/Windows
Vulnerability Description
Windows 10 version 1709 and above are affected by this vulnerability
The vulnerability is caused by improper structure settings during the processing of the ICMPv6 protocol, leading to a stack overflow
Vulnerability Impact
Attackers can exploit this vulnerability to gain the highest system privileges R3(System) and kernel privileges (R0)
Device Model

Analysis of Windows TCP/IP Remote Code Execution Vulnerability (CVE-2020-16898)

Introduction
The Windows TCP/IP handler runs at the kernel level with the driver file named TCPIP.sys
This vulnerability primarily exists in the TCP/IP stack when processing the 0x19 recursive DNS server option, where the length field of the ICMPv6 IPv6 routing broadcast packet is even. The processing logic has a flaw that allows it to bypass security checks, resulting in a stack overflow. By carefully crafting code, arbitrary code can be executed on the target host.
This article focuses on vulnerability analysis. Due to space constraints, it will not delve into details of the IPv6 protocol and other specifics. Please refer to RFC documents for more information.
Prerequisite Knowledge
ICMPv6
0 1 2 40 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Type | Code | Checksum |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| |Message Body +| |RDNSS Option0 1 2 30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Type | Length | Reserved |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Lifetime |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| |: Addresses of IPv6 Recursive DNS Servers :| |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Among them, the RDNSS Option’s Type must be set to 0x19, indicating it is RDNSS
The Length represents the length, which should normally satisfy (Length – 1) % 2 = 0. The cause of this vulnerability is due to a calculation error that leads to the execution of unchecked Options packets that are too long, resulting in fragmentation and sending NdisGetDataBuffer, copying memory to the stack, which causes stack overflow.
typedef struct _NET_BUFFER {.....0x18 ULONG DataLength;0x28 ULONG DataOffset.....} NET_BUFFER, *PNET_BUFFER;PVOID NdisGetDataBuffer(PNET_BUFFER NetBuffer,ULONG BytesNeeded,PVOID Storage,UINT AlignMultiple,UINT AlignOffset);
NdisGetDataBuffer returns a pointer to the data
If Storage is fragmented and the data is not contiguous, this pointer will be used to store the data.
Vulnerability Analysis
IDA Static Analysis:
tcpip!Ipv6pHandleRouterAdvertisement
First, the verification checks if the HopLimit in the IP packet is not 0xFF, then the function ends.

Analysis of Windows TCP/IP Remote Code Execution Vulnerability (CVE-2020-16898)

Verification checks if the ICMPv6 Code is not empty, then the function ends.

Analysis of Windows TCP/IP Remote Code Execution Vulnerability (CVE-2020-16898)

This function contains two Switch loops. The first Switch loop verifies the Packet structure for correctness, reading the length and Type for verification, which is the main cause of the vulnerability.
If Length is even and set to 4, after the first verification is complete, it will read the content at offset +32 bytes.

Analysis of Windows TCP/IP Remote Code Execution Vulnerability (CVE-2020-16898)

This means that it treats our specially set DNS address as the properties of the second IPv6 Options. We only need to set a reasonable property to bypass its security check and achieve any function in the call list.
case 0x19:        if ( *(_BYTE *)(v12 + 0x194) < 0 && (RDNSS_Header_Length < 0x18u)          *v8 = 0x19;        break;
We only need to set the packet so that Length * 8 > 0x18.
“\x03\xcc\xb2\xb3\xb4\xb5\xb6\xb7\x19\xCC\x00\x00\xbc\xbd\xbe\xbf”
Here, the author sets it to 0xCC to lay the groundwork for the stack overflow below.

Analysis of Windows TCP/IP Remote Code Execution Vulnerability (CVE-2020-16898)

Next, by implementing the function’s Switch loop, we call the TcpIP!Ipv6pUpdateRDNSS function, which, when calculating the IPv6 DNS Server address, uses our carefully designed Length which, through incorrect calculations, causes a deviation in the number of DNS Server addresses in the Address field, leading to incorrect offsets in the NET_BUFFER structure in NdisGetDataBuffer, causing it to read incorrect memory.
Here, Length is set to 0x04, and according to this algorithm, the resulting value is 0x01, which means it believes there is only one set of DNS Server addresses, and the loop processes only once.
tcpip!Ipv6pUpdateRDNSS

Analysis of Windows TCP/IP Remote Code Execution Vulnerability (CVE-2020-16898)

The function NetioAdvanceNetBuffer is designed to add the DataOffset in the NET_BUFFER structure with parameter 2, representing an increase in offset, and reduce Length to prevent out-of-bounds read/write (OOB{RW}).
Here, DataOffset += 8 points to RDNSS_Option.Address.
The function then reads 0x10 bytes and increases its offset by 0x10. This is the key point that causes the vulnerability because we do not align according to 16 bytes. The value we set is 0x04, which is even, and it pushes forward 0x10 bytes, performs some operations, and then ends the function.
DataOffset += 0x10; now DataOffset is offset by 0x18, which is the beginning of the second DNS Server, and then the function ends, returning to the upper function tcpip!Ipv6pHandleRouterAdvertisement.

Analysis of Windows TCP/IP Remote Code Execution Vulnerability (CVE-2020-16898)

At this point, DataOffset points to:
At this time, our Length and Options can be set arbitrarily because Ipv6pUpdateRDNSS incorrectly calculated the offset.
“\x03\xcc\xb2\xb3\xb4\xb5\xb6\xb7\x19\xCC\x00\x00\xbc\xbd\xbe\xbf”

Analysis of Windows TCP/IP Remote Code Execution Vulnerability (CVE-2020-16898)

After reading, the value of Opts_aaxxx is 0xcc * 8.
Entering the Switch loop case 3:
&v216 is stack space with only 0x20 bytes, while our Length is 0x660 bytes long, calling NdisGetDataBuffer function leads to a stack overflow.
However, one very important point to note is that, as mentioned earlier, NdisGetDataBuffer saves data in parameter 3 only if the data is non-contiguous and not within a single packet; otherwise, it will not save the data in parameter 3.
The length of the Packet we send is 1680 bytes, which is greater than the current NIC MTU, so it is automatically fragmented and sent without considering this issue.
Finally running .\CVE-2020-16898.exe IPv6
Successfully crashed

Analysis of Windows TCP/IP Remote Code Execution Vulnerability (CVE-2020-16898)

Patch Information
https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-16898
In kb4580328,
tcpip!Ipv6pHandleRouterAdvertisement
The function adds a check that Length * 8 must be a multiple of 0x10 to prevent malicious packets.
RDNSS Optionscase 0x19:if ( (_BYTE )(v12 + 0x194) < 0 && (RDNSS_Header_Length < 0x18u || ((_BYTE)RDNSS_Header_Length - 8) & 0xF) )*v8 = 0x19;break;
References
IPv6 Protocol Document
ICMPv6 Protocol Document
MSRC:
https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-16898
Original Source: Anheng Information Security Research Institute

Analysis of Windows TCP/IP Remote Code Execution Vulnerability (CVE-2020-16898)

Leave a Comment