快速搭建自用dnslog

快速搭建自用dnslog

前言

dnslog是常见的辅助验证漏洞的手段,为什么要自建dnslog?

  • 第三方dnslog在一些特殊时期会受到一股神秘力量影响变得不稳定甚至不能用
  • 有些业务或者信息不方便使用第三方平台
  • 常见的dnslog平台会被安全产品检测到

网上已经有很多开源的dnslog平台,且有不少的dnslog搭建教程,但是看下来感觉还是有点麻烦,而且不容易集成到自己平台。对于个人来说,很多步骤其实是可以省略的。前几天原来的dnslog的域名到期了,又重新买了个新的重新搭建了一次。正好分享一下我是如何快速搭建个人使用的dnslog的。

搭建dnslog

搭建需求
  1. 一个公网ip(建议国外)
  2. 一个域名(建议国外)
dns配置解析

只需要两条配置

  1. A记录,host自定,此处用ns演示,指向公网ip
  2. NS记录,host自定,此处用log演示,指向第一步的域名 即ns.域名

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Oyqjk5pv-1650507622951)(uUbfbAMyWMsx40fMqLl-K6Gx45f-7CJTDfRD7SDtk60.png)]

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 查看输出,发现打印结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lpLStRzl-1650507622952)(s-yf9-TyfQrfc5F23brYRf4ROHjceKXd4N0d1k6OjxM.png)]

至此,如果只做个人的即时验证的话,dnslog已经搭建完毕,用的时候开一下,用完了关了就完事了。

但是如果给自动化验证用的话,还是需要增加保存和查询功能。

增加记录和查询功能

首先是保存记录,上一步已经成功打印了,那么直接把输出的代码改成保存结果的代码就完事了。sqlite、mysql、mongo甚至直接保存到txt也行,开心就好。比如保存到redis

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ulaFWBEb-1650507622952)(CE_RltmMNIOrvk8by_uWz-qwXFBt1mrRb410MpI3JUU.png)]

保存成功就剩查询功能了,有了保存位置,随便写个查询接口就完事了。php,python,go,java哪个顺手用哪个。 比如用python的flask写个仿ceye的查询接口:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kqK83TUG-1650507622953)(nNIYJfVJa-Nhe-C61IXicwisho31Nlh4PSwqZZFnUQU.png)]

调用接口试一下,莫得问题~

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tMsasKvp-1650507622953)(YByXg98_TEUA0-fS_Ietffq_ornSf9uDmMkO4hgekRA.png)]

集成到自己的平台

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WhkI948v-1650507622953)(cFzlEh017kzJUESiXKcw4eClXCqpA0LXotk2LNkjfJg.png)]

往期文章

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值