Skip to content

Native Kerberos relay via DNS CNAME abuse (CVE-2026-20929): coercion -> AP-REQ relay -> AD CS (ESC8) certificate #21693

Description

@Pushpenderrathore

Summary

Add native Kerberos authentication-relay support to Metasploit. Metasploit's relay stack is NTLM-only today (http_server/relay/ntlm, smb/relay_server); there is no Kerberos relay anywhere in modules/ or lib/msf/. This tracks the work to coerce a Windows client into a Kerberos AP-REQ, relay that AP-REQ to a real service (AD CS Web Enrollment / ESC8), and obtain a client-auth certificate for the coerced principal, end to end, natively, with no external PoC dependency (mitm6 / krbrelayx).

Endorsed by @jheysel-r7 for the GSoC 2026 Kerberos track. It builds directly on the existing ESC8 relay target (auxiliary/server/relay/esc8.rb) and the per-protocol kerberos/service_authenticator/* clients.

Background: CVE-2026-20929

CVE-2026-20929 (disclosed by Cymulate) is a Kerberos relay technique. When a Windows client resolves a hostname and DNS returns a CNAME, the client builds its Kerberos SPN from the canonical (CNAME-target) name. An on-path attacker who controls DNS answers returns a CNAME pointing the victim's lookup at an attacker-chosen SPN host (e.g. the AD CS server) plus A/AAAA records that steer the connection. The victim then requests a service ticket for the attacker-chosen SPN, connects to the attacker, and authenticates with an AP-REQ. Because the SPN in the ticket matches the relay target, the target accepts the relayed AP-REQ.

Microsoft's January 2026 patch added Channel Binding (EPA/CBT) to HTTP.sys, which ties the AP-REQ to the outer TLS channel and breaks relay to HTTPS endpoints that enforce it. It does not address the coercion (by-design, same stance as NTLM relay), and does not cover targets that don't enforce channel binding: LDAP without signing/EPA, SMB, or plain-HTTP ESC8 /certsrv, which has no TLS channel to bind. That plain-HTTP ESC8 leg is the primary target here.

Officially, CVE-2026-20929 is catalogued as Improper access control in Windows HTTP.sys (CWE-284, EoP over a network; CVSS 7.5, GHSA-cjjj-mhw7-f4xr), the terse MSRC framing of the HTTP.sys leg the January 2026 channel-binding patch fixed. "Kerberos relay via DNS CNAME abuse" (Cymulate) is the research name for the technique behind it. This module targets the residual surface the patch does not cover (the coercion, which is by-design, plus relay to non-CBT targets such as plain-HTTP ESC8), not the patched HTTP.sys path.

Attack chain

  1. Coercion: rogue IPv6 RA + DHCPv6 make the attacker the victim's DNS; the DNS responder answers with a CNAME to the attacker-chosen SPN host (+ A/AAAA).
  2. Kerberos relay: capture the victim's AP-REQ over SMB, extract it from the SPNEGO/GSS blob as opaque DER, rebuild it into a fresh GSS-SPNEGO blob for the target. (Unlike NTLM, an AP-REQ is a single self-contained message with no challenge/response.)
  3. AD CS enrollment (ESC8): replay the AP-REQ to /certsrv via Authorization: Negotiate; the relayed connection is authenticated for its lifetime, so the existing HTTP::WebEnrollment code requests the certificate unchanged.
  4. Outcome: a client-auth certificate for the coerced account (a durable, PKINIT-capable credential), or shadow-credentials / RBCD via an LDAP target.

PKINIT / S4U2Self / S4U2Proxy already exist in the framework and are the downstream consumers of the issued certificate; they are not part of this work. The new contribution is the coercion plus the Kerberos AP-REQ relay handler; everything downstream is reuse.

Design (mirrors the NTLM relay stack)

Separate the relay server (carries only a Kerberos AP-REQ, agnostic to how the auth was coerced and to which target consumes it) from the relay targets (small create_client factory, one branch per protocol). This is the same server/target separation the NTLM stack uses, so a future Kerberos relay workflow (KrbRelayUp-shaped) drops in by adding a target rather than editing the server. Coercion is a separate module from the relay server; either half is usable alone.

Two design decisions the lab PoC forced (both baked in):

  • Decouple the ticket SPN from the relay destination. Read the SPN from the AP-REQ, but let the target host/URL be set independently (krbrelayx forces them equal, needing a decoy-name + /etc/hosts workaround).
  • Own CSR generation with a maintained crypto API (Ruby OpenSSL::X509::Request / the existing WebEnrollment code), not impacket's removed pyOpenSSL.crypto.X509Req.

Implementation (three PRs)

The work is split into three PRs against master, in review order:

Phase PR Scope
Phase 1 #21709 Kerberos relay stack + ESC8 (AD CS Web Enrollment) target
Phase 2 #21724 Native DHCPv6 DNS-takeover coercion
Phase 3 #21725 Rogue IPv6 RA + RDNSS DNS-takeover coercion

Phase 1 (#21709) mirrors the NTLM namespace one file at a time under relay/kerberos and smb/relay/kerberos: an SMB server captures the AP-REQ from the SMB2 SessionSetup, GSS code extracts and rebuilds it as opaque DER, a one-shot relay handler falls through to NTLM for non-Kerberos tokens, and a create_client target factory feeds an HTTP target client that replays over Authorization: Negotiate. The ESC8 target module (auxiliary/server/relay/esc8_kerberos.rb) reuses the existing HTTP::WebEnrollment mixin unchanged.

Phase 2 (#21724) is the coercion half: a new Rex::Proto::DHCPv6 library (RFC 8415 + RFC 3646) plus a DHCPv6 DNS-takeover module (auxiliary/spoof/dhcp/dhcpv6_dns_takeover.rb) that reuses DNS::Server behind a shared DNS::NamePoisoner mixin, poisoning names under a target domain while forwarding everything else so the victim stays functional.

Phase 3 (#21725) adds the rogue RA / RDNSS primitive (RFC 8106) for networks where DHCPv6 is filtered or ignored, reusing the same NamePoisoner mixin. It is stacked on Phase 2 and should be reviewed after it.

Phases 2 and 3 carry no dependency on Phase 1 and can be reviewed independently. The relay half and the coercion half are each usable alone, which is why they are separate modules rather than one.

Placement notes for reviewers: ESC8 Kerberos is a separate module (not a RELAY_PROTO switch on esc8.rb) because the NTLM module mixes in an NTLM-specific relay server at class-definition time. The DHCPv6 takeover lives under auxiliary/spoof/dhcp (it coerces, it doesn't relay).

Checklist

Lab validation status

Validated live: capturing a real SMB2 AP-REQ, round-tripping it byte-identical through the GSS code, rebuilding it into a Negotiate header, and driving AD CS Web Enrollment to issue a certificate for the coerced machine account with no knowledge of its credentials. DNS/CNAME coercion is separately confirmed on the wire (mitm6 wins primary DNS, names poisoned).

Pending live validation (all identified): the exact SMB2 SessionSetup response to the coerced client; the DHCPv6 multicast bind + group join (privileged socket, real interface); a domain-joined victim adopting the rogue DHCPv6 DNS; and the full coerce->relay->cert chain, which additionally needs the CA and KDC on different hosts; on the single combined-host lab, poisoning that host also cuts the victim off from the KDC.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    StaleMarks an issue as stale, to be closed if no action is taken

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions