用dig命令辨别DNS是否被污染

原理

既然说起 DNS 和其污染问题,就不得不先看看 DNS 系统是如何工作的,这个自从上个世纪80出现的方便大家连接主机的系统的确是有问题。从 Wikipedia 上偷张图先。

563px-An_example_of_theoretical_DNS_recursion.svg_

DNS 解析流程图

图中可以看到我们的 ISP 的 DNS 服务器在图中叫做 DNS Recurser,在解析一个域名的时候,总共经过了以下的步骤,图是以 www.wikipedia.org 作为示范的:

  1. 向 root 服务器获取该 gTLD 的管辖服务器,图中为 org 结尾的域名
  2. root 服务器返回 org 的管辖服务器
  3. 向 org 的管辖服务器查询,谁来负责解析 wikipedia.org 这个域名的
  4. org 的管辖服务器返回解析 wikipedia.org 的服务器 IP 地址
  5. 向 wikipedia.org 的解析服务器发出查询,解析 www.wikipedia.org 的 IP 地址
  6. 拿到最终要的 IP 地址

共6个步骤。那么如果在最后一次查询的时候,有人假冒了 wikipedia.org 的解析服务器,则可以在中间进行欺骗攻击,致使用户最后得到的 IP 地址不是真实的地址。如图所示,

563px-An_example_of_theoretical_DNS_recursion.svg_1

解析请求被劫持

更详细的关于 DNS 的内容,可以自行参考 rfc1035(http://tools.ietf.org/html/rfc1035)。

手工模拟

以上是大致的解析原理,我们手工一步一步来模拟解析的每个步骤吧。这里我用的环境是北京联通 ADSL + Mac OS X 10.7 『Lion』 + 某国家 VPN 一条。工具用到了 dig 和 tcpdump 来完成,Windows 下默认木有俩工具似乎,大家自行寻找吧,或者找一个 GNU/Linux 发行版装上,个人推荐 Ubuntu,有 red hat 情节的,就 Fedora 好了。首先用联通的 ADSL 来试验下

$ dig //直接获取根服务器的地址


; <<>> DiG 9.8.3-P1 <<>>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59858
;; flags: qr rd ra; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 3

;; QUESTION SECTION:
;.				IN	NS

;; ANSWER SECTION:
.			205043	IN	NS	e.root-servers.net.
.			205043	IN	NS	h.root-servers.net.
.			205043	IN	NS	l.root-servers.net.
.			205043	IN	NS	i.root-servers.net.
.			205043	IN	NS	a.root-servers.net.
.			205043	IN	NS	d.root-servers.net.
.			205043	IN	NS	c.root-servers.net.
.			205043	IN	NS	b.root-servers.net.
.			205043	IN	NS	j.root-servers.net.
.			205043	IN	NS	k.root-servers.net.
.			205043	IN	NS	g.root-servers.net.
.			205043	IN	NS	m.root-servers.net.
.			205043	IN	NS	f.root-servers.net.

;; ADDITIONAL SECTION:
k.root-servers.net.	604222	IN	AAAA	2001:7fd::1
m.root-servers.net.	602881	IN	A	202.12.27.33
f.root-servers.net.	604218	IN	AAAA	2001:500:2f::f

;; Query time: 11 msec
;; SERVER: 202.96.134.133#53(202.96.134.133)
;; WHEN: Wed Sep 27 15:56:19 2017
;; MSG SIZE  rcvd: 300

这里我们可以看到,全球的域名根服务器共有从 a 到 m,共 13 组服务器。继续去 dig 出来这些服务器的地址吧,随便找一个好了

$ dig e.root-servers.net

; <<>> DiG 9.8.3-P1 <<>> e.root-servers.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25194
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;e.root-servers.net.		IN	A

;; ANSWER SECTION:
e.root-servers.net.	84796	IN	A	192.203.230.10

;; Query time: 4 msec
;; SERVER: 202.96.134.133#53(202.96.134.133)
;; WHEN: Wed Sep 27 15:56:51 2017
;; MSG SIZE  rcvd: 52

这里我们抓到了其中一组的 DNS 根服务器 e.root-servers.net 的地址为 192.203.230.10,继续

$ dig -t ns @192.203.230.10 com.

; <<>> DiG 9.8.3-P1 <<>> -t ns @192.203.230.10 com.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 691
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 13, ADDITIONAL: 15
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;com.				IN	NS

;; AUTHORITY SECTION:
com.			172800	IN	NS	a.gtld-servers.net.
com.			172800	IN	NS	b.gtld-servers.net.
com.			172800	IN	NS	c.gtld-servers.net.
com.			172800	IN	NS	d.gtld-servers.net.
com.			172800	IN	NS	e.gtld-servers.net.
com.			172800	IN	NS	f.gtld-servers.net.
com.			172800	IN	NS	g.gtld-servers.net.
com.			172800	IN	NS	h.gtld-servers.net.
com.			172800	IN	NS	i.gtld-servers.net.
com.			172800	IN	NS	j.gtld-servers.net.
com.			172800	IN	NS	k.gtld-servers.net.
com.			172800	IN	NS	l.gtld-servers.net.
com.			172800	IN	NS	m.gtld-servers.net.

;; ADDITIONAL SECTION:
a.gtld-servers.net.	172800	IN	A	192.5.6.30
b.gtld-servers.net.	172800	IN	A	192.33.14.30
c.gtld-servers.net.	172800	IN	A	192.26.92.30
d.gtld-servers.net.	172800	IN	A	192.31.80.30
e.gtld-servers.net.	172800	IN	A	192.12.94.30
f.gtld-servers.net.	172800	IN	A	192.35.51.30
g.gtld-servers.net.	172800	IN	A	192.42.93.30
h.gtld-servers.net.	172800	IN	A	192.54.112.30
i.gtld-servers.net.	172800	IN	A	192.43.172.30
j.gtld-servers.net.	172800	IN	A	192.48.79.30
k.gtld-servers.net.	172800	IN	A	192.52.178.30
l.gtld-servers.net.	172800	IN	A	192.41.162.30
m.gtld-servers.net.	172800	IN	A	192.55.83.30
a.gtld-servers.net.	172800	IN	AAAA	2001:503:a83e::2:30
b.gtld-servers.net.	172800	IN	AAAA	2001:503:231d::2:30

;; Query time: 349 msec
;; SERVER: 192.203.230.10#53(192.203.230.10)
;; WHEN: Wed Sep 27 15:57:39 2017
;; MSG SIZE  rcvd: 509

上面共有从 a 到 m,一样是 13 组服务器在所有的 com. 的 gTLD 的记录保存。

$ dig -t ns @192.5.6.30 twitter.com

; <<>> DiG 9.8.3-P1 <<>> -t ns @192.5.6.30 twitter.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21761
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;twitter.com.			IN	NS

;; ANSWER SECTION:
twitter.com.		240	IN	A	78.16.49.15

;; Query time: 13 msec
;; SERVER: 192.5.6.30#53(192.5.6.30)
;; WHEN: Wed Sep 27 15:58:18 2017
;; MSG SIZE  rcvd: 45

这里看到问题了么?本来应该返回 twitter.com 的具体的解析服务器,为什么直接返回了一个 A 记录?而且还是这么诡异的一个地址?查询以下这个 IP 的归属地,是『新西兰 奥克兰Telstraclear公司』,应该是胡乱编出来的地址了。至此再测试下去意义也就不大了,具体原因等会儿分析。换上 VPN 看看结果如何

$ dig

# 这里的结果完全一样,我们继续选择 e 的那组


$ dig e.root-servers.net

# 嗯,这里也一样,继续


$ dig -t ns @192.203.230.10 com.

# 没有什么新奇的,继续…

以上几条结果都是一样的返回

$ dig -t ns @192.5.6.30 twitter.com

; <<>> DiG 9.8.3-P1 <<>> -t ns @192.5.6.30 twitter.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56292
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 6
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;twitter.com.			IN	NS

;; AUTHORITY SECTION:
twitter.com.		172800	IN	NS	ns3.p34.dynect.net.
twitter.com.		172800	IN	NS	ns4.p34.dynect.net.
twitter.com.		172800	IN	NS	r01-01.ns.twtrdns.net.
twitter.com.		172800	IN	NS	r01-02.ns.twtrdns.net.
twitter.com.		172800	IN	NS	d01-01.ns.twtrdns.net.
twitter.com.		172800	IN	NS	d01-02.ns.twtrdns.net.

;; ADDITIONAL SECTION:
ns3.p34.dynect.net.	172800	IN	A	208.78.71.34
ns4.p34.dynect.net.	172800	IN	A	204.13.251.34
r01-01.ns.twtrdns.net.	172800	IN	A	205.251.195.113
r01-02.ns.twtrdns.net.	172800	IN	A	205.251.197.74
d01-01.ns.twtrdns.net.	172800	IN	A	208.78.70.34
d01-02.ns.twtrdns.net.	172800	IN	A	204.13.250.34

;; Query time: 171 msec
;; SERVER: 192.5.6.30#53(192.5.6.30)
;; WHEN: Wed Sep 27 16:00:31 2017
;; MSG SIZE  rcvd: 270

到这里的结果就和刚才不一样了,可以看到,192.5.6.30 这个服务器正常返回了应该负责解析 twitter.com 的真实 ns 的服务器,既然都做到这里了,就继续下去吧,继续从里面随便抓一个出来

$ dig @208.78.71.34 twitter.com any
;; Truncated, retrying in TCP mode.

; <<>> DiG 9.8.3-P1 <<>> @208.78.71.34 twitter.com any
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16674
;; flags: qr aa rd; QUERY: 1, ANSWER: 28, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;twitter.com.			IN	ANY

;; ANSWER SECTION:
twitter.com.		293	IN	SOA	ns1.p26.dynect.net. zone-admin.dyndns.com. 2007137844 3600 600 604800 60
twitter.com.		13999	IN	NS	ns2.p34.dynect.net.
twitter.com.		13999	IN	NS	r01-02.ns.twtrdns.net.
twitter.com.		13999	IN	NS	r01-01.ns.twtrdns.net.
twitter.com.		13999	IN	NS	d01-02.ns.twtrdns.net.
twitter.com.		13999	IN	NS	d01-01.ns.twtrdns.net.
twitter.com.		13999	IN	NS	ns3.p34.dynect.net.
twitter.com.		13999	IN	NS	ns1.p34.dynect.net.
twitter.com.		13999	IN	NS	ns4.p34.dynect.net.
twitter.com.		79	IN	A	199.59.148.10
twitter.com.		79	IN	A	199.16.156.6
twitter.com.		79	IN	A	199.59.150.7
twitter.com.		79	IN	A	199.16.156.102
twitter.com.		79	IN	A	199.16.156.38
twitter.com.		79	IN	A	199.16.156.70
twitter.com.		79	IN	A	199.59.149.198
twitter.com.		79	IN	A	199.16.156.198
twitter.com.		79	IN	A	199.59.149.230
twitter.com.		79	IN	A	199.59.148.82
twitter.com.		79	IN	A	199.16.156.230
twitter.com.		79	IN	A	199.59.150.39
twitter.com.		300	IN	TXT	"v=spf1 ip4:199.16.156.0/22 ip4:199.59.148.0/22 ip4:8.25.194.0/23 ip4:8.25.196.0/23 ip4:204.92.114.203 ip4:204.92.114.204/31 ip4:23.21.83.90 include:_spf.google.com include:_thirdparty.twitter.com -all"
twitter.com.		300	IN	TXT	"google-site-verification=h6dJIv0HXjLOkGAotLAWEzvoi9SxqP4vjpx98vrCvvQ"
twitter.com.		600	IN	MX	10 aspmx.l.google.com.
twitter.com.		600	IN	MX	20 alt2.aspmx.l.google.com.
twitter.com.		600	IN	MX	30 ASPMX3.GOOGLEMAIL.COM.
twitter.com.		600	IN	MX	20 alt1.aspmx.l.google.com.
twitter.com.		600	IN	MX	30 ASPMX2.GOOGLEMAIL.COM.

;; Query time: 21 msec
;; SERVER: 208.78.71.34#53(208.78.71.34)
;; WHEN: Wed Sep 27 16:01:08 2017
;; MSG SIZE  rcvd: 891

我们可以发现挂上 VPN 之后的解析流程才是正确无误的过程,但是为什么不挂上就不能正确解析?自然是 DNS 服务器被污染了。并且拦截的方式似乎也很弱智,发现 UDP 53 口的包带有 twitter.com 字样,直接返回一个随即、胡编出来的 IP 地址,也不管人家到底是不是直接要去查 twitter.com 的 A 记录。为了证明这种猜想,继续做一些试验吧。不如发一个错误的 DNS 包出去,看看返回什么结果。

$ dig @202.204.49.251 twitter.com -t ns --->> 查询的服务器是 202.204.48.251

; <<>> DiG 9.8.3-P1 <<>> @202.204.49.251 twitter.com -t ns
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28290
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;twitter.com.			IN	NS

;; ANSWER SECTION:
twitter.com.		64	IN	A	243.185.187.39

;; Query time: 24 msec
;; SERVER: 202.204.49.251#53(202.204.49.251)
;; WHEN: Wed Sep 27 16:02:43 2017
;; MSG SIZE  rcvd: 45

这里的服务器是 iBeiKe 在教育网内的服务器,对于外网没有开除了 80 的任何口,而且也没有 53 的 UDP 开着,果然,够弱智!

tcpdump 抓包

tcpdump 这个东西虽然叫做 tcpdump,但是 UDP 抓起来也没有问题,随便抓抓 DNS 的解析包,不需要什么重型武器,这种轻量级别就很好用了。环境和上面一样,我用的无线网络,所以在 Mac OS X 的接口就是 en1 了。不上 VPN 看看结果如何吧

$ sudo tcpdump -i en1 -vvv udp

16:05:10.189549 IP (tos 0x0, ttl 64, id 51997, offset 0, flags [none], proto UDP (17), length 57)
    192.168.0.86.61289 > a.gtld-servers.net.domain: [udp sum ok] 4731+ NS? twitter.com. (29)
16:05:10.190103 IP (tos 0x0, ttl 255, id 51444, offset 0, flags [none], proto UDP (17), length 69)
    192.168.0.86.53167 > ns.szptt.net.cn.domain: [udp sum ok] 14187+ PTR? 30.6.5.192.in-addr.arpa. (41)
16:05:10.200364 IP (tos 0x0, ttl 45, id 59500, offset 0, flags [DF], proto UDP (17), length 73)

# 假的结果返回

    a.gtld-servers.net.domain > 192.168.0.86.61289: [udp sum ok] 4731 q: NS? twitter.com. 1/0/0 twitter.com. [1m38s] A 59.24.3.173 (45)
16:05:10.201166 IP (tos 0x0, ttl 197, id 55906, offset 0, flags [none], proto UDP (17), length 84)
    a.gtld-servers.net.domain > 192.168.0.86.61289: [udp sum ok] 4731* q: NS? twitter.com. 1/0/0 twitter.com. [1m] A 59.24.3.174 (56)
16:05:10.258033 IP (tos 0x0, ttl 51, id 56581, offset 0, flags [none], proto UDP (17), length 298)

# 正确的返回

    a.gtld-servers.net.domain > 192.168.0.86.61289: [udp sum ok] 4731- q: NS? twitter.com. 0/6/6 ns: twitter.com. [2d] NS ns3.p34.dynect.net., twitter.com. [2d] NS ns4.p34.dynect.net., twitter.com. [2d] NS r01-01.ns.twtrdns.net., twitter.com. [2d] NS r01-02.ns.twtrdns.net., twitter.com. [2d] NS d01-01.ns.twtrdns.net., twitter.com. [2d] NS d01-02.ns.twtrdns.net. ar: ns3.p34.dynect.net. [2d] A 208.78.71.34, ns4.p34.dynect.net. [2d] A 204.13.251.34, r01-01.ns.twtrdns.net. [2d] A 205.251.195.113, r01-02.ns.twtrdns.net. [2d] A 205.251.197.74, d01-01.ns.twtrdns.net. [2d] A 208.78.70.34, d01-02.ns.twtrdns.net. [2d] A 204.13.250.34 (270)
16:05:10.429786 IP (tos 0x0, ttl 51, id 0, offset 0, flags [none], proto UDP (17), length 73)

    a.gtld-servers.net.domain > 192.168.0.86.61289: [udp sum ok] 4731 q: NS? twitter.com. 1/0/0 twitter.com. [3m29s] A 78.16.49.15 (45)
16:05:10.718695 IP (tos 0x0, ttl 59, id 0, offset 0, flags [DF], proto UDP (17), length 101)
    ns.szptt.net.cn.domain > 192.168.0.86.53167: [udp sum ok] 14187 q: PTR? 30.6.5.192.in-addr.arpa. 1/0/0 30.6.5.192.in-addr.arpa. [1d] PTR a.gtld-servers.net. (73)
16:05:11.124993 IP (tos 0x0, ttl 4, id 27621, offset 0, flags [none], proto UDP (17), length 157)
    192.168.0.119.63409 > 239.255.255.250.ssdp: [udp sum ok] UDP, length 129
16:05:11.125357 IP (tos 0x0, ttl 1, id 29662, offset 0, flags [none], proto UDP (17), length 304)
    192.168.0.149.50587 > 239.255.255.250.ssdp: [udp sum ok] UDP, length 276
16:05:11.227349 IP (tos 0x0, ttl 4, id 27623, offset 0, flags [none], proto UDP (17), length 157)
    192.168.0.119.63409 > 239.255.255.250.ssdp: [udp sum ok] UDP, length 129

唔,有人抢在正确的包之前跑来了。你为什么这么积极呢?为什么呢…

转自:https://2.botu.me/post/2763.html