Skip to content

Add rogue IPv6 RA + RDNSS DNS-takeover coercion (CVE-2026-20929) - #21725

Draft
Pushpenderrathore wants to merge 7 commits into
rapid7:masterfrom
Pushpenderrathore:feature/ipv6-ra-dns-takeover
Draft

Add rogue IPv6 RA + RDNSS DNS-takeover coercion (CVE-2026-20929)#21725
Pushpenderrathore wants to merge 7 commits into
rapid7:masterfrom
Pushpenderrathore:feature/ipv6-ra-dns-takeover

Conversation

@Pushpenderrathore

Copy link
Copy Markdown
Contributor

Part of #21693.

Third of a stacked series adding native Kerberos authentication relay to Metasploit. #21709 contributes the relay stack and the ESC8 target, #21724 contributes the DHCPv6 coercion half, and this PR adds the Router Advertisement coercion half.

Stacked on #21724. This branch contains that PR's commits, so the diff here shows both until #21724 lands. The RA specific work is the top three commits. Review #21724 first.

Description

auxiliary/spoof/ipv6/ipv6_ra_dns_takeover runs a rogue IPv6 router that advertises the attacker as the recursive DNS server via the RDNSS option (RFC 8106) inside Router Advertisements, paired with the same DNS poisoner used by the DHCPv6 module.

It is the Router Advertisement equivalent of the mitm6 style DHCPv6 takeover. Rather than answering DHCPv6 Solicits it multicasts RAs carrying an RDNSS option, which modern Windows and other RFC 8106 clients adopt as their IPv6 resolver. Two behaviours worth calling out:

  • It listens for Router Solicitations and replies with a unicast RA immediately, so a client is coerced when it boots or refreshes rather than waiting for the next unsolicited advertisement.
  • By default the RA advertises a router lifetime of 0, so it does not claim to be a default router. Routing is left alone and only DNS is taken over. That keeps the victim network functional and the footprint small.

Having both coercion paths matters because they fail in different places. DHCPv6 needs the client to actually run a DHCPv6 client, and RDNSS needs the client to honour RFC 8106. Between them the coverage across Windows versions and configurations is much better than either alone.

Related Issue: #21693

Breaking Changes

None.

Reviewer Notes

Shared code with #21724: Msf::Exploit::Remote::DNS::NamePoisoner holds the poison-under-a-domain plus forward-everything-else behaviour, and both modules use it. It was extracted in #21724 rather than duplicated here.

lib/msf/core/exploit/remote/ipv6.rb gains the RA and RDNSS construction used by this module.

Opened as a draft for the same reason as #21724. Unit coverage is green, but the full coerce to relay to certificate chain is not yet validated end to end, which needs a two host lab with the CA separate from the KDC.

Verification Steps

    • bundle exec rspec spec/lib/rex/proto/dhcpv6 spec/lib/msf/core/exploit/remote/ipv6_spec.rb spec/modules/auxiliary/spoof and confirm no failures.
    • use auxiliary/spoof/ipv6/ipv6_ra_dns_takeover, set DOMAIN to a lab domain, run. Confirm the DNS server reports it is poisoning names under that domain.
    • From an RFC 8106 capable client on the same segment, confirm the attacker appears as an IPv6 DNS server after an RA is received (netsh interface ipv6 show dnsservers on Windows).
    • Send a Router Solicitation from the client, by disabling and re-enabling its interface, and confirm a unicast RA is answered immediately rather than after the next multicast interval.
    • Confirm the default route is unchanged, since router lifetime is 0 by default.

Test Evidence

$ bundle exec rspec spec/lib/rex/proto/dhcpv6 \
    spec/lib/msf/core/exploit/remote/ipv6_spec.rb \
    spec/modules/auxiliary/spoof
57 examples, 0 failures

$ ruby tools/dev/msftidy.rb modules/auxiliary/spoof/ipv6/ipv6_ra_dns_takeover.rb
1 file inspected, no offenses detected

Environment

Field Details
Operating System macOS 15 (Darwin 25.5.0), Ruby 3.3.8
Target Software/Hardware RFC 8106 capable IPv6 client on the same segment

Pre-Submission Checklist

  • Included a corresponding documentation markdown file in documentation/modules (new modules only)
  • No sensitive information (IP addresses, credentials, API keys, hashes) in code or documentation
  • Tested on the target environment specified in the Environment section above (unit coverage green, full lab chain still pending, see Reviewer Notes)
  • Included RSpec tests for library changes (encouraged for lib/ changes)
  • Read the CONTRIBUTING.md and module acceptance guidelines

Provide the native coercion half of the Kerberos relay via DNS
(CVE-2026-20929), removing the dependency on external tooling like mitm6:

- Add Rex::Proto::DHCPv6, a native DHCPv6 packet library (RFC 8415 plus
  the RFC 3646 DNS options): message/option encoding and helpers to build
  the rogue server responses that hand a client the attacker as its DNS
  server.
- Add Rex::Proto::DHCPv6::Server, a reusable rogue DHCPv6 server that
  answers Solicit/Request/Renew/Rebind/Confirm/Information-Request.
- Add auxiliary/spoof/dhcp/dhcpv6_dns_takeover, which runs the rogue
  DHCPv6 server and a paired DNS server that poisons names under a target
  domain (A/AAAA or a CNAME for the DNS-CNAME relay trick) while
  forwarding all other lookups so the victim stays functional.
Two defects found while validating the rogue DHCPv6 server against a live
client on the lab network:

- The multicast group join packed the interface index in network byte
  order, so on little-endian hosts the kernel joined on interface 0 and
  the server never received the multicast Solicit. Pack it in native
  byte order to match struct ipv6_mreq.
- The client address was read assuming recvfrom always returns an address
  array, but older rex-socket versions return the host string directly,
  so the reply went to a malformed destination. Handle both shapes.

With these fixes a cross-host Solicit is answered with an Advertise
addressed correctly to the client on udp/546, handing out the attacker as
the DNS server.
Move the selective DNS poisoning behaviour out of the DHCPv6 DNS takeover
module into a reusable DNS::NamePoisoner mixin (TARGET_DOMAIN, TARGET_HOSTS,
SPOOF_IP6, RELAY_CNAME plus the on_dispatch_request poison/forward logic and
the IPv6 validation helper), so the upcoming Router Advertisement takeover
module can share the exact same coercion behaviour instead of duplicating it.

The DHCPv6 module now just includes the mixin and keeps its DHCPv6-specific
options and server wiring. No behaviour change; its spec is unchanged and green.
Add the Router Advertisement equivalent of the mitm6 DHCPv6 DNS takeover, a
second native coercion primitive for the Kerberos relay via DNS technique
(CVE-2026-20929) with no external tooling dependency.

The Ipv6 mixin gains RFC 8106 builders: ipv6_build_rdnss_option (Recursive DNS
Server option), ipv6_build_dnssl_search_option (DNS search list), and
ipv6_build_ra_dns_packet, which assembles an ICMPv6 RA advertising the attacker
as the IPv6 resolver. Router lifetime defaults to 0 so routing is untouched and
only DNS is taken over; the existing DNSSL command-injection builder is left
intact.

The new auxiliary/spoof/ipv6/ipv6_ra_dns_takeover module multicasts these RAs on
an interval while the shared DNS::NamePoisoner server poisons names under the
target domain and forwards everything else, keeping the victim functional.

Adds 20 specs for the RDNSS/DNSSL/RA builders and the module wiring; loads clean
in msfconsole, rubocop and msftidy clean.
Add a Router Solicitation responder so a client is coerced the moment it boots
or refreshes instead of waiting for the next unsolicited advertisement.

The Ipv6 mixin gains ipv6_router_solicitation? (ICMPv6 type 133 detection,
reading PacketFu's icmpv6_type) and ipv6_solicited_ra_target, which applies RFC
4861 section 6.2.6: unicast the reply to the solicitor, or multicast to
all-nodes when the solicitation source is the unspecified address.
ipv6_build_ra_dns_packet now takes optional dst_mac/dst_addr so the same builder
produces both the multicast unsolicited RA and a unicast solicited reply.

The module now runs a single capture thread that multicasts the unsolicited RA
on the interval while filtering for RS (BPF icmp6 and ip6[40] == 133) and
replying immediately, keeping all pcap access on one handle. A RESPOND_TO_SOLICITS
option (default true) gates the responder.

Adds 9 specs (RS detection, solicited-target selection, unicast vs multicast
reply, nil/non-solicitation handling); rubocop and msftidy clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

1 participant