CVE-2020-16898 — Windows TCP/IP ICMPv6 Router Advertisement RCE (“Bad Neighbor”)

Last updated: 2026-04-15
Severity: Critical (CVSS 9.8)
Component: tcpip.sys (ICMPv6 / NDP)
Bug Class: Heap-Based Buffer Overflow (OOB Write)
Privilege Escalation: Remote → Kernel RCE (zero-click)
Patch: October 13, 2020 (KB4580386, Patch Tuesday)
Related: Tcpip Stack, Cve 2024 38063, Cve 2021 24086, Integer Overflows
Tags: kernel-mode, heap-overflow, oob-write, integer-overflow, tcpip, remote


Vulnerability Summary

A remote code execution vulnerability in the Windows TCP/IP kernel driver (tcpip.sys) triggered by a specially crafted ICMPv6 Router Advertisement (RA) packet containing a malformed RDNSS (Recursive DNS Server) option. No authentication or user interaction required; zero-click. Named “Bad Neighbor” by McAfee. CVSS 9.8.

Affected: Windows 10 (all versions to patch), Windows Server 2019, 2016, 2012 R2, 2008 R2. Any host that can receive ICMPv6 Router Advertisements on a network segment is vulnerable.

Discovered by Tal Be’ery and independent researchers. First public PoC and blog by pi3 (blog.pi3.com.pl). Zeek-based network detector by Corelight.


Root Cause Analysis

RDNSS Option Background

ICMPv6 Router Advertisement messages (NDP, RFC 4861) may carry option type 25 (RDNSS — Recursive DNS Server) as defined by RFC 8106. The RDNSS option format:

 0                   1                   2                   3
 0 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=25   |    Length     |           Reserved            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           Lifetime                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
:            Addresses of IPv6 Recursive DNS Servers            :
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

The Length field is in units of 8 bytes. The header (Type + Length + Reserved + Lifetime) = 8 bytes. Each IPv6 address = 16 bytes. Therefore:

  • Minimum valid length = 3 (= 24 bytes = 8-byte header + 1×16-byte address)
  • Length must be odd (since 8 + 16n bytes → length = 1 + 2n, always odd)

RFC requirement: Length ≥ 3 and Length must be odd.

The Vulnerability

Windows tcpip.sys did not validate that the RDNSS option Length field:

  1. Is ≥ 3 (minimum for at least one address)
  2. Is odd (RFC-mandated)

An attacker crafts an RDNSS option with Length = 1 (8 bytes total) or Length = 0 or an even Length. The Windows implementation computes the number of embedded IPv6 addresses as:

// Approximate vulnerable logic:
num_addresses = (Length * 8 - sizeof(RDNSS_header)) / sizeof(IPv6_addr);
// With Length = 1: (8 - 8) / 16 = 0  → no addresses parsed (but...
// With Length = 2: (16 - 8) / 16 = 0.5 → truncated → boundary issues
// With odd large Length using even sub-steps: size miscalculation → OOB

The precise mechanism: when Length is even (invalid per RFC), the size arithmetic produces a misaligned or incorrect count of addresses. The parsing code reads/copies IPv6 address data from the packet into a kernel heap buffer that is too small for the number of addresses it actually processes, causing a heap-based buffer overflow into adjacent kernel pool memory.

An attacker with IPv6 network adjacency sends a single crafted ICMPv6 RA packet with the malformed RDNSS option, triggering the overflow.

Why Windows Firewall Doesn’t Help

Router Advertisements are processed at the network layer before the Windows Firewall layer. The firewall operates above the IP layer and cannot block ICMPv6 RA processing in tcpip.sys. An attacker on the same local network segment (or link) can trigger this regardless of firewall rules.


Exploitation Technique

DoS

Trivial: send a single crafted ICMPv6 RA with Length = 0 or even Length RDNSS option → immediate BSOD.

RCE Path

The heap overflow occurs in kernel pool memory. The path to RCE follows standard kernel pool exploitation:

  1. KASLR defeat: Requires an information leak to determine kernel object addresses. The overflow itself may provide a leak if the corrupted adjacent object contains a kernel pointer.
  2. Heap grooming: Coerce the allocator to place a useful victim structure (function pointer table, token, etc.) adjacent to the RDNSS buffer before the RA is sent.
  3. Overwrite: Send crafted RA with controlled RDNSS data to overflow into the victim object.

The overflow data is directly attacker-controlled (the RDNSS option payload = IPv6 addresses = arbitrary 16-byte aligned chunks of attacker data). This provides a clean, controllable overflow primitive.

Key exploit constraint: The attacker must be on the same link (Layer 2 segment) as the target for the ICMPv6 RA to be delivered, unless routers forward RA packets (non-default; RFC 4861 discourages forwarding RA between links). This limits the attack surface to:

  • Same LAN/VLAN
  • VPN connections that forward RA
  • Cloud environments with shared L2

Key Primitives Used

  • Invalid RDNSS option (Length not odd, or < 3) → size miscalculation
  • Controllable kernel heap overflow: attacker-supplied IPv6 addresses as overflow data
  • Adjacent pool object corruption: function pointers, EPROCESS token pointers, etc.

Mitigations Bypassed

  • Zero-click (no user interaction)
  • Windows Firewall is ineffective (RA processed below firewall layer)
  • KASLR must be defeated separately for reliable RCE

Detection

Corelight/Zeek detection package (github.com/corelight/CVE-2020-16898):

  • Detects exploit attempts by examining ICMPv6 RA option fields in network traffic
  • Pattern: RDNSS option (type=25) with even length or length < 3
  • Alert: "CVE-2020-16898 exploit detected from [source]"
  • Usage: zeek -Cr scripts/__load__.zeek capture.pcap

Snort/IDS signatures were also published by several vendors within days of disclosure.


Proof-of-Concept Notes

ResourceAuthorNotes
blog.pi3.com.pl/?p=780pi3First public blog + PoC
github.com/corelight/CVE-2020-16898CorelightZeek detection package (not exploit)

Patch Analysis

  • Patch: KB4580386 (October 2020 Patch Tuesday)
  • Fix: Added RFC-conformance validation in the RDNSS option parser: Length must be ≥ 3 AND odd. If invalid, option is discarded without processing.
  • Impact: Silently drop malformed RA options; does not send ICMP error (to avoid amplification risk).

Historical Context

“Bad Neighbor” is part of a line of critical Windows TCP/IP vulnerabilities:

  • CVE-2020-16898 (Oct 2020) — ICMPv6 RA / RDNSS OOB write (RCE)
  • CVE-2021-24086 (Feb 2021) — IPv6 nested fragment NULL deref (DoS)
  • CVE-2021-24094 (Feb 2021) — IPv6 recursive reassembly UAF + firewall bypass
  • CVE-2024-38063 (Aug 2024) — IPv6 coalescing integer underflow → heap overflow (RCE/DoS)

The pattern: each vulnerability exploits increasing complexity in the IPv6 header parsing pipeline in tcpip.sys, with each successive bug requiring deeper knowledge of tcpip.sys internals.


References

  • pi3, “CVE-2020-16898 – Exploiting ‘Bad Neighbor’ vulnerability”, blog.pi3.com.pl, October 2020
  • Corelight, CVE-2020-16898 detection package, github.com/corelight/CVE-2020-16898, 2020
  • McAfee Labs, “Bad Neighbor: The Windows ICMPv6 Router Advertisement Vulnerability”, 2020
  • RFC 8106, “IPv6 Router Advertisement Options for DNS Configuration”, 2017
  • MSRC, “CVE-2020-16898 — Windows TCP/IP Remote Code Execution Vulnerability”, October 2020
  • Axel “0vercl0k” Souchet, (discusses Bad Neighbor context in CVE-2021-24086 blog), 2021