快速搭建自用dnslog
前言
dnslog是常见的辅助验证漏洞的手段,为什么要自建dnslog?
- 第三方dnslog在一些特殊时期会受到一股神秘力量影响变得不稳定甚至不能用
- 有些业务或者信息不方便使用第三方平台
- 常见的dnslog平台会被安全产品检测到
网上已经有很多开源的dnslog平台,且有不少的dnslog搭建教程,但是看下来感觉还是有点麻烦,而且不容易集成到自己平台。对于个人来说,很多步骤其实是可以省略的。前几天原来的dnslog的域名到期了,又重新买了个新的重新搭建了一次。正好分享一下我是如何快速搭建个人使用的dnslog的。
搭建dnslog
搭建需求
- 一个公网ip(建议国外)
- 一个域名(建议国外)
dns配置解析
只需要两条配置
- A记录,host自定,此处用ns演示,指向公网ip
- NS记录,host自定,此处用log演示,指向第一步的域名 即
ns.域名
dnslog脚本
dnslog记录脚本代码如下:
# -*- coding: utf-8 -*-
import copy
import os
import tempfile
from dnslib import RR, QTYPE, RCODE, TXT
from dnslib.server import DNSServer, DNSHandler, BaseResolver, DNSLogger
DNS_DOMAIN = 'xxxx.pw' # 主域名
# 记录管理的域名
# NS域名
NS1_DOMAIN = 'ns.xxxx.pw' # ns域名
NS2_DOMAIN = NS1_DOMAIN
# 服务器监听地址
SERVER_IP = '0.0.0.0'
class RedisLogger():
def log_data(self, dnsobj):
pass
def log_error(self, handler, e):
pass
def log_pass(self, *args):
pass
def log_prefix(self, handler):
pass
def log_recv(self, handler, data):
pass
def log_reply(self, handler, reply):
pass
def log_request(self, handler, request):
domain = request.q.qname.__str__().lower().rstrip('.')
print('new dnslog : domain--->{} \t type--->{} \t ip--->{}'.format(domain,QTYPE[request.q.qtype],handler.client_address[0]))
def log_send(self, handler, data):
pass
def log_truncated(self, handler, reply):
pass
class ZoneResolver(BaseResolver):
"""
Simple fixed zone file resolver.
"""
def __init__(self, zone, glob=False):
"""
Initialise resolver from zone file.
Stores RRs as a list of (label,type,rr) tuples
If 'glob' is True use glob match against zone file
"""
self.zone = [(rr.rname, QTYPE[rr.rtype], rr)
for rr in RR.fromZone(zone)]
self.glob = glob
self.eq = 'matchGlob' if glob else '__eq__'
def resolve(self, request, handler):
"""
Respond to DNS request - parameters are request packet & handler.
Method is expected to return DNS response
"""
reply = request.reply()
qname = request.q.qname
qtype = QTYPE[request.q.qtype]
if qtype == 'TXT':
txtpath = os.path.join(tempfile.gettempdir(), str(qname).lower())
if os.path.isfile(txtpath):
reply.add_answer(
RR(qname, QTYPE.TXT, rdata=TXT(open(txtpath).read().strip())))
for name, rtype, rr in self.zone:
# Check if label & type match
if getattr(qname,
self.eq)(name) and (qtype == rtype or qtype == 'ANY'
or rtype == 'CNAME'):
# If we have a glob match fix reply label
if self.glob:
a = copy.copy(rr)
a.rname = qname
reply.add_answer(a)
else:
reply.add_answer(rr)
# Check for A/AAAA records associated with reply and
# add in additional section
if rtype in ['CNAME', 'NS', 'MX', 'PTR']:
for a_name, a_rtype, a_rr in self.zone:
if a_name == rr.rdata.label and a_rtype in [
'A', 'AAAA'
]:
reply.add_ar(a_rr)
if not reply.rr:
reply.header.rcode = RCODE.NXDOMAIN
return reply
def main():
zone = '''
*.{dnsdomain}. IN NS {ns1domain}.
*.{dnsdomain}. IN NS {ns2domain}.
*.{dnsdomain}. IN A {serverip}
{dnsdomain}. IN A {serverip}
'''.format(
dnsdomain=DNS_DOMAIN,
ns1domain=NS1_DOMAIN,
ns2domain=NS2_DOMAIN,
serverip=SERVER_IP)
resolver = ZoneResolver(zone, True)
logger = RedisLogger()
print("Starting Zone Resolver (%s:%d) [%s]" % ("*", 53, "UDP"))
udp_server = DNSServer(resolver, port=53, address='', logger=logger)
udp_server.start()
if __name__ == '__main__':
main()
测试
ping 这个dnslog 查看输出,发现打印结果
至此,如果只做个人的即时验证的话,dnslog已经搭建完毕,用的时候开一下,用完了关了就完事了。
但是如果给自动化验证用的话,还是需要增加保存和查询功能。
增加记录和查询功能
首先是保存记录,上一步已经成功打印了,那么直接把输出的代码改成保存结果的代码就完事了。sqlite、mysql、mongo甚至直接保存到txt也行,开心就好。比如保存到redis
保存成功就剩查询功能了,有了保存位置,随便写个查询接口就完事了。php,python,go,java哪个顺手用哪个。 比如用python的flask写个仿ceye的查询接口:
调用接口试一下,莫得问题~