aws-route53-dangling-alias-takeover

A dangling alias or CNAME record pointing to a deprovisioned AWS resource enables subdomain takeover - an attacker (unauthenticated, from the internet) claims the deprovisioned resource and serves content on the hijacked name without any AWS IAM permission required.

derived aws emits ExposedToInternet

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'zone': None} ContainsResourceReference {'target_resource': None}

where

node_type(?zone) == DNS ?zone.provider_type == 'AWS::Route53::HostedZone' ?zone.properties.has_dangling_alias == true ?target_resource.state == 'deprovisioned' or ?target_resource is not found in inventory ?zone.properties.dangling_record_types contains 'A (alias)' OR ?zone.properties.dangling_record_types contains 'AAAA (alias)' OR ?zone.properties.dangling_record_types contains 'CNAME'

emit

source typeDNS
target typeAnonymousIdentity
source?zone
targetpublic-internet
conditionsservice_state
state logicCONDITIONAL(service_state) — the dangling record exists (confirmed by inventory cross-reference showing the alias target is absent from collected resources) but actual exploitability depends on whether the target resource type is claimable: S3 static website bucket (same-name, same-region) -> ACTIVE if bucket is unclaimed; CloudFront distribution CNAME -> ACTIVE if no current distribution claims the alternate domain; API Gateway custom domain -> CONDITIONAL (requires ownership verification via DNS TXT record as of 2022, which may not be present on the attacker's domain); ELB/ALB DNS name -> CONDITIONAL (random suffix, hard to claim); EIP -> CONDITIONAL until confirmed released. Never BLOCKED (no IAM permission exists to prevent an external attacker from claiming an unclaimed resource).

Narrative

Hosted zone {zone.name} contains a dangling alias/CNAME record pointing to a deprovisioned AWS resource. An attacker who claims that resource (e.g. creates a new S3 bucket with the same name, or a new CloudFront distribution using the same alternate domain) will serve content and/or capture traffic under the hijacked subdomain - no Route 53 permission required.

Raw rule rules/derived/aws/route53.yaml

id: aws-route53-dangling-alias-takeover
emits: ExposedToInternet
description: "A dangling alias or CNAME record pointing to a deprovisioned AWS resource enables subdomain\
  \ takeover \u2014 an attacker (unauthenticated, from the internet) claims the deprovisioned resource\
  \ and serves content on the hijacked name without any AWS IAM permission required."
applies_to:
- aws
match:
- - zone: null
  - ContainsResourceReference
  - target_resource: null
where:
- node_type(?zone) == DNS
- ?zone.provider_type == 'AWS::Route53::HostedZone'
- ?zone.properties.has_dangling_alias == true
- ?target_resource.state == 'deprovisioned' or ?target_resource is not found in inventory
- ?zone.properties.dangling_record_types contains 'A (alias)' OR ?zone.properties.dangling_record_types
  contains 'AAAA (alias)' OR ?zone.properties.dangling_record_types contains 'CNAME'
emit:
  source_type: DNS
  target_type: AnonymousIdentity
  source: ?zone
  target: public-internet
  permissions: []
  conditions:
  - service_state
  state_logic: "CONDITIONAL(service_state) \u2014 the dangling record exists (confirmed by inventory cross-reference\
    \ showing the alias target is absent from collected resources) but actual exploitability depends on\
    \ whether the target resource type is claimable: S3 static website bucket (same-name, same-region)\
    \ -> ACTIVE if bucket is unclaimed; CloudFront distribution CNAME -> ACTIVE if no current distribution\
    \ claims the alternate domain; API Gateway custom domain -> CONDITIONAL (requires ownership verification\
    \ via DNS TXT record as of 2022, which may not be present on the attacker's domain); ELB/ALB DNS name\
    \ -> CONDITIONAL (random suffix, hard to claim); EIP -> CONDITIONAL until confirmed released. Never\
    \ BLOCKED (no IAM permission exists to prevent an external attacker from claiming an unclaimed resource)."
  confidence: 0.8
  derived_from:
  - ?zone ContainsResourceReference ?target_resource (dangling alias/CNAME)
  false_positive_note: "This edge requires CROSS-REFERENCING the alias/CNAME target against live resource\
    \ inventory (ELB, CloudFront, S3, API GW). Do NOT emit based solely on a record existing \u2014 the\
    \ target must be confirmed absent from the account's collected resources. Claimability varies by resource\
    \ type (see state_logic above). ELB DNS names with random suffixes are generally NOT claimable by\
    \ re-creating an ELB \u2014 downgrade those to CONDITIONAL or POTENTIAL. No IAM permission is required\
    \ for this attack path, so BLOCKED state is not applicable. This edge does not yield CanEnterAccount\
    \ directly \u2014 it enables traffic capture on the hijacked name, which is a pre-condition for out-of-band\
    \ credential theft. Cite can-control.yaml: Controls roll-up is NOT appropriate here."
  narrative: "Hosted zone {zone.name} contains a dangling alias/CNAME record pointing to a deprovisioned\
    \ AWS resource. An attacker who claims that resource (e.g. creates a new S3 bucket with the same name,\
    \ or a new CloudFront distribution using the same alternate domain) will serve content and/or capture\
    \ traffic under the hijacked subdomain \u2014 no Route 53 permission required."
move · open · esc close