DOT/DOH服务探测识别

不见归来 ,相思寄于山海!

  由于合规要求,我需要探测公司哪些主机上运行了DOT、DOH服务,而nmap暂时识别不出这两个服务指纹,无奈只能自己动手了。DOT即(DNS over TLS),DOH即(DNS over HTTPS),这两者都是DNS加密服务,由于我也是第一次接触它们,因此费了一番时间查阅资料,在此记录。

为什么需要DNS加密

  DNS是互联网中最基本的协议,可以解析域名成IP地址,使用范围非常广。如果dns解析请求过程没有进行加密,被中间人截取dns请求流量后,就可以进行劫持、钓鱼、监控用户浏览的站点。

DOH VS DOT

  两者有点类似,都是用来加密dns请求流量。IETF已将HTTPS上的DNS定义为RFC8484,并将其通过TLS定义为RFC7858和RFC8310。DOT使用TCP作为基本连接协议,并通过TLS加密和身份验证进行分层。DOH默认端口是443,基于HTTPS协议;DOT默认端口是853,基于tcp协议。

如何识别DOT、DOH服务

  前面说到DOT默认开853端口,因此只要扫描主机是否开了853端口,或者扫描全端口后识别哪些端口为domain服务即可。但DOH默认开443端口,nmap探测返回的是https服务指纹,因此很难加以判断识别。唯一的方式就是模拟DOH标准协议的dns请求,观察是否能够正常返回解析结果。但是构造标准的请求包需要研究具体协议以及原理,难度很大,好在已经有人用python写了一个这方面的库。

doh-proxy

  官方PYPI:https://pypi.org/project/doh-proxy/#doh-client
  doh-proxy是专门用来代理doh的库,它分为服务端工具与客户端工具,安装完成后,自带了doh-proxy、doh-client,重点关注一下doh-client,可以模拟发起使用doh加密的dns请求。目前只支持>python3.5,用pip直接安装即可。

1
$ pip install doh-proxy

使用命令

1
$ doh-client --domain 1.1.1.1 --qname thief.one --dnssec


  如果运行没有报错,则说明1.1.1.1的443端口支持doh服务,替换1.1.1.1为要识别的主机IP即可识别出主机的443端口是否提供了DOH服务。如果想要批量扫描主机,可以修改site-packages/dohproxy目录下的client.py文件,比如像下面这样:

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import asyncio
import dns.message
import time
import signal
from dohproxy import client_protocol, utils
class Client(client_protocol.StubServerProtocol):
def on_answer(self, addr, msg):
try:
print(dns.message.from_wire(msg))
except Exception:
self.logger.exception(msg)
def parse_args():
parser = utils.client_parser_base()
parser.add_argument(
'--qname',
default='example.com',
help='Name to query for. Default [%(default)s]',
)
parser.add_argument(
'--qtype',
default='AAAA',
help='Type of query. Default [%(default)s]',
)
parser.add_argument(
'--dnssec',
action='store_true',
help='Enable DNSSEC validation.'
)
return parser.parse_args()
def build_query(args):
dnsq = dns.message.make_query(
qname=args.qname,
rdtype=args.qtype,
want_dnssec=args.dnssec,
)
dnsq.id = 0
return dnsq
def func_time(timeout=10):
def run_func(func):
def handler(signum, frame):
raise AssertionError
def wrapper(*args,**kwargs):
try:
signal.signal(signal.SIGALRM, handler)
signal.alarm(timeout)
return func(*args,**kwargs)
except AssertionError:
print(func.__name__+" Function run Timeout","Warning")
return wrapper
return run_func
def main_sync(args):
logger = utils.configure_logger('doh-client', level=args.level)
client = Client(args=args, logger=logger)
loop = asyncio.get_event_loop()
loop.run_until_complete(client.make_request(None, build_query(args)))
class test():
domain = "1.1.1.1"
qname = "thief.one"
port = 443
level = "DEBUG"
qtype = "AAAA"
dnssec = True
insecure = False
cafile = None
remote_address = None
uri = "/dns-query"
post = False
debug = False
@func_time(timeout=10)
def main(domain):
args = test()
args.domain = domain
try:
main_sync(args)
return True
except Exception as e:
print(e)
return False
if __name__ == '__main__':
domain_list = ["1.1.1.1","2.2.2.2"]
for domain in domain_list:
print(main(domain))

然后运行python client.py文件。

参考文章

https://www.racent.com/blog/dns-over-tls-vs-dns-over-https/
https://program-think.blogspot.com/2018/10/Comparison-of-DNS-Protocols.html
https://zhuanlan.zhihu.com/p/47170371

本文标题:DOT/DOH服务探测识别

文章作者:nmask

发布时间:2019年07月09日 - 17:07

最后更新:2019年07月09日 - 17:07

原始链接:https://thief.one/2019/07/09/1/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

nmask wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
坚持原创技术分享,您的支持将鼓励我继续创作!

热门文章推荐: