ADSTALE-011: DNS Record Staleness

Platform
Active Directory
Category
AD Stale & Obsolete Objects
Severity
Medium
Zero Trust pillar
Governance (weight 0)
Golden fixtures
3
Branch coverage
Observed: fixtures prove the verdicts they exercise
Provenance
baseline

What it checks

The check reads the DNS server configuration and every AD-integrated forward and reverse zone using Get-DnsServer, Get-DnsServerZone, Get-DnsServerZoneAging, and Get-DnsServerResourceRecord. For each zone it evaluates: - ScavengingState and ScavengingInterval on the server (Get-DnsServerScavenging) - Aging enabled flag on the zone (Get-DnsServerZoneAging -Name <zone>) - NoRefreshInterval (default 7 days) and RefreshInterval (default 7 days) - AllowUpdate value (the zone must be Secure dynamic update to be AD-integrated and safely scavenged) - Per-record TimeStamp on A, AAAA, and PTR records. A non-zero TimeStamp marks the record as dynamic and eligible for scavenging; a TimeStamp of zero (0) marks the record as static and exempt. - Age of each dynamic record computed as (Get-Date) minus TimeStamp, flagged if it exceeds the configured staleness threshold (default 30 days, which is no-refresh 7 + refresh 7 + a 16-day safety margin). - DnsAdmins group membership cross-reference for context on who can edit zone data. The audit also identifies orphan PTR records in reverse-lookup zones that point to A records which no longer exist, and A records whose IPv4 target now sits in a DHCP scope (which makes opportunistic claim trivial). Static records on perimeter, ADCS, ADFS, Exchange, and SCCM hosts are surfaced for review because they are commonly left static years after the underlying host is decommissioned. The check is read-only: it queries via the DNS Server PowerShell module against each DC or designated DNS server and emits no zone modifications.

Why it matters

DNS is a trust anchor for intranet authentication. Windows clients silently negotiate Kerberos and NTLM against whatever IP a hostname resolves to, and most internal web applications, file shares, and management consoles do not pin TLS certificates or validate the server identity beyond the hostname-to-IP DNS lookup. When a DNS record outlives the host it pointed to, three exposure paths open. First, IP reclaim: an attacker on the same subnet (or with influence over a flat DHCP scope, a cloud VPC, or a sloppily decommissioned VM pool) can claim the abandoned IPv4 address and immediately receive every connection still resolving the stale name. This is the classic subdomain takeover pattern moved inside the perimeter. Second, NTLM coercion and relay: tools such as PetitPotam, PrinterBug, and DFSCoerce can coerce a Windows host to authenticate to an arbitrary name; if that name resolves to attacker-controlled infrastructure thanks to a stale record, the authentication is relayed to ADCS Web Enrollment, LDAP, or SMB on a real target and converts to a certificate or a session. Third, credential and data theft via impersonation: intranet portals (helpdesk, SharePoint, Confluence, Jenkins, internal IdP, legacy OWA) routinely use Windows Integrated Authentication, so any browser silently passes the NTLM challenge or Kerberos ticket to the attacker the moment the user types the old URL. Stale records also defeat detection: SIEM rules keyed on hostnames trust the DNS answer, so traffic to the attacker arrives labelled with the legitimate decommissioned host name. Because DNS scavenging is off by default on every Windows DNS server and every zone created with it, this exposure accumulates silently for the life of the forest unless explicitly remediated.

Attack path

Step 1: Reconnaissance. An attacker with any authenticated foothold (or even an unauthenticated attacker on the LAN with a captured netlogon broadcast) enumerates the DNS zone. AD-integrated zones are world-readable by Authenticated Users: a single zone transfer via dnscmd /ZoneExport, an AXFR if allowed, or an LDAP query against CN=MicrosoftDNS,CN=System,DC=domain pulls every record name, type, and timestamp. Tools such as adidnsdump (dirkjanm), PowerView Get-DomainDNSRecord, and BloodHound CE collection extract the same data. Step 2: Stale-record triage. The attacker filters for A and AAAA records whose timestamp is older than the password-policy or patch-cycle horizon (90 days is a typical threshold). They cross-reference the target IPv4 address against the DHCP scope range, the cloud VPC CIDR, or a recently decommissioned hypervisor pool. Records pointing into a DHCP scope are top priority because the address can be requested back trivially. Step 3: IP acquisition. The attacker requests the orphan IPv4 address. Inside a DHCP scope this is a matter of releasing the current lease and requesting the desired address, or running a DHCP starvation that exhausts the pool and forces the server to hand back the wanted address. Inside a cloud VPC it is a matter of provisioning a new ENI with the desired private IP. On a flat segment with static addressing it is a matter of plugging in and self-assigning. Step 4: Service impersonation. The attacker stands up the service the original host ran (a simple SMB responder, an HTTP listener with NTLM challenge enabled, an LDAP bind capture, or Responder / ntlmrelayx in relay mode) on the newly claimed IP. Any client that resolves the stale name and connects now hands the attacker a credential or a session. Step 5: Coercion amplification. The attacker uses PetitPotam, PrinterBug, DFSCoerce, or the WebDav abuse path to coerce specific high-value computer accounts (DCs, ADFS servers, ADCS CAs) to authenticate to a UNC path whose hostname is a stale A record they now control. The coerced authentication is relayed via ntlmrelayx to ADCS Web Enrollment, which issues a certificate for the coerced machine account, which converts to a Kerberos TGT via PKINIT and to DCSync against the domain. Step 6: Persistence. The attacker leaves the stale-record claim in place. Because the record is still in DNS, still timestamped (or not, if the attacker triggers a dynamic update from the squatting host), and still resolves cleanly, defenders investigating the original incident often miss that the DNS record itself is the persistence primitive.

How Guerrilla assesses it

Guerrilla loads the DnsServer PowerShell module and queries each Domain Controller (or the AD-integrated DNS server set) for server-wide aging configuration (Get-DnsServerScavenging) and per-zone aging configuration (Get-DnsServerZoneAging on every zone returned by Get-DnsServerZone where ZoneType is Primary and IsDsIntegrated is True). For each AD-integrated zone the check enumerates every resource record via Get-DnsServerResourceRecord -ZoneName <zone> -RRType A,AAAA,PTR, reads the TimeStamp property on each record, and computes (Get-Date).ToUniversalTime() minus TimeStamp. Records where TimeStamp is null or zero are reported as static (eligible for manual review but exempt from scavenging by design). Records where the timestamp delta exceeds the configured threshold are reported as stale. The check separately validates that AllowUpdate equals 2 (Secure only) on each AD-integrated zone, that ScavengingInterval is non-zero on at least one DNS server, and that NoRefreshInterval and RefreshInterval sum to a value that matches the configured threshold. Reverse lookup zones are walked to identify PTR records whose paired A record no longer exists. The check also queries the DnsAdmins group membership and surfaces any non-Tier-0 members for cross-reference with ADPRIV checks. All queries are read-only and run against the DNS-server RPC interface or LDAP, requiring authenticated-user access plus DNS read rights, which the Authenticated Users principal holds on AD-integrated zones by default.

Recommended value

DNS scavenging enabled with appropriate no-refresh and refresh intervals; no stale DNS records older than 30 days

Remediation

Enable DNS scavenging on the DNS server properties and on each AD-integrated DNS zone. Configure the no-refresh interval to 7 days and the refresh interval to 7 days. Set scavenging period on at least one DNS server. Manually review aged DNS records before the first scavenging run to identify critical static records that need to be excluded. Mark records that should not be scavenged as static

Fixture-proven verdicts

Every verdict below is proven by a golden fixture in the module's gating test suite. This table derives from the last green run; it cannot be edited by hand.

Verdict scenarios for ADSTALE-011
ScenarioExpected verdict
cleanPASS
known-badWARN
throttledNot Assessed

Framework mappings

NIST SP 800-53
CM-2
CIS AD Benchmark
9.5.3