DNSLOG平臺搭建從0到1

廣州錦行科技發表於2020-06-27

作者:saltor

1 前言

       DNSLOG是一種回顯機制,常用於在某些漏洞無法回顯但可以發起DNS請求的情況下,利用此方式外帶資料,以解決某些漏洞由於無回顯而難以利用的問題。主要利用場景有SQL盲注、無回顯的命令執行、無回顯的SSRF。本文介紹一種搭建DNSLOG平臺的方法,旨在為滲透測試提供一些幫助。

2 前期準備

      一個域名,一臺vps

      本文使用的是:阿里雲購買的域名和雲伺服器ECS

      域名:example.icu

      vps ip:100.100.100.100

3 實驗過程

3.1 新增DNS解析

      在雲解析DNS處新增一條A記錄和一條NS記錄,如圖所示:

DNSLOG平臺搭建從0到1

3.2 對外開放53埠

      在雲伺服器ECS安全組規則裡新增對外開發53埠的規則,協議是udp。

DNSLOG平臺搭建從0到1

3.3 DNSLOG程式碼

      dnslog.py

      執行在python2下,無需安裝依賴包。

      #!/usr/bin/env python

      # -*- coding: utf-8 -*-

      import SocketServer

      import struct

      import socket as socketlib

      # DNS Query

      class SinDNSQuery:

         def __init__(self, data):

             i = 1

             self.name = ”

             while True:

                 d = ord(data[i])

                 if d == 0:

                     break;

                 if d < 32:

                     self.name =self.name + ‘.’

                 else:

                     self.name =self.name + chr(d)

                 i = i + 1

              self.querybytes =data[0:i + 1]

              (self.type,self.classify) = struct.unpack(‘>HH’, data[i + 1:i + 5])

              self.len = i + 5

          def getbytes(self):

              return self.querybytes+ struct.pack(‘>HH’, self.type, self.classify)

      # DNS Answer RRS

      class SinDNSAnswer:

          def __init__(self, ip):

             self.name = 49164

              self.type = 1

              self.classify = 1

              self.timetolive = 190

             self.datalength = 4

              self.ip = ip

          def getbytes(self):

              res =struct.pack(‘>HHHLH’, self.name, self.type, self.classify, self.timetolive,self.datalength)

              s = self.ip.split(‘.’)

              res = res +struct.pack(‘BBBB’, int(s[0]), int(s[1]), int(s[2]), int(s[3]))

              return res

      # DNS frame

      class SinDNSFrame:

          def __init__(self, data):

              (self.id, self.flags,self.quests, self.answers, self.author, self.addition) =struct.unpack(‘>HHHHHH’, data[0:12])

              self.query =SinDNSQuery(data[12:])

          def getname(self):

              return self.query.name

          def setip(self, ip):

              self.answer =SinDNSAnswer(ip)

             self.answers = 1

              self.flags = 33152

          def getbytes(self):

              res =struct.pack(‘>HHHHHH’, self.id, self.flags, self.quests, self.answers,self.author, self.addition)

              res = res +self.query.getbytes()

              if self.answers != 0:

                  res = res +self.answer.getbytes()

              return res

      # A UDPHandler to handle DNS query

      class SinDNSUDPHandler(SocketServer.BaseRequestHandler):

          def handle(self):

             data =self.request[0].strip()

              dns =SinDNSFrame(data)

              socket =self.request[1]

              namemap =SinDNSServer.namemap

              if(dns.query.type==1):

                 # If this is query a A record, thenresponse it        

                 name =dns.getname();

                  toip =namemap['*']

                  dns.setip(toip)

                  print ‘%s:%s–>%s’%(self.client_address[0], name, toip)

                  socket.sendto(dns.getbytes(),self.client_address)

              else:

                  # If this is notquery a A record, ignore it

                 socket.sendto(data, self.client_address)

      # DNS Server

      class SinDNSServer:

          def __init__(self,port=53):

     SinDNSServer.namemap ={}

              self.port = port

          def addname(self, name,ip):

             SinDNSServer.namemap[name] = ip

          def start(self):

              HOST, PORT =”0.0.0.0″, self.port

              server =SocketServer.UDPServer((HOST, PORT), SinDNSUDPHandler)

              server.serve_forever()

      if __name__ == “__main__”:

          sev = SinDNSServer()

          sev.addname(‘*’,’127.0.0.1′) # default address

          sev.start() # start DNSserver

      在vps上直接執行dnslog.py,一個簡易的DNSLOG平臺就搭起來了。

      執行效果如下圖:

DNSLOG平臺搭建從0到1 

     回顯的ip地址可透過sev.addname(‘*’, ’127.0.0.1′)自定義。

4 WEB介面

      使用tornado框架寫一個web介面。

      專案已上傳至github:https://github.com/sa1tor/dnslog

      pip安裝tornado之後直接執行server.py即可,當然也可以使用Nginx+Tornado+Supervisor來進行部署。

      pip install tornado

      python server.py

      預設在8000埠,瀏覽器訪問http://ip:8000/ 即可看到web介面

      我指定了6002埠,python server.py –port=6002

DNSLOG平臺搭建從0到1

      介面比較簡單,只有3個按鈕,getsubdomain按鈕用來獲取隨機子域名,refresh按鈕用來重新整理頁面,delete all按鈕用來刪除所有記錄。

5 後記

      網上的相關實驗大多數都是使用兩個域名來實現的,一個域名修改DNS伺服器,另一個域名修改NS記錄。不過其實只用一個域名也是可以的。

      修改DNS伺服器如下圖:

DNSLOG平臺搭建從0到1

相關文章