DNS隧道通信的檢測


DNS隧道通信的檢測



DNS 隧道通信


DNS 隧道通信是C&C常用的通信方式,一般常用的編碼方式Base64,Binary編碼,NetBios編碼等,Hex編碼等。且請求的Type一般都是txt(為了返回的時候能夠加入更多的信息)。payload部分一般是子域名。攻擊者自己控一個域的DNS權威應答服務器,然后等待失陷主機請求域名,本地DNS服務器迭代查詢轉發請求到那台權威DNS,從而實現失陷主機與C&C Server的通信。

DNS 檢測方案


+  頻率大:一般遠超正常的DNS頻率;
+  不重復:一般子域名變化很多,很少重復;但不排除網絡不通一直發送前幾個指令的請求;
+  文本類型:一般為了傳輸更多數據,使用TXT類型;
+  域名很長,有一段base64、2進制或16進制的編碼段的域名;

備注: 可以根據以上做個打分,但是打分機制還沒有想好,下面代碼中只是一個小例子
+ 規則一:domain長度大於52,每增加一個,增加0.5分;
+ 規則二:出現出去26個字符和點以及-的字符串,則乘以2;
+ 規則三:如果請求type是TXT則嚴重懷疑,分數乘以2;

代碼


https://github.com/cisp/DNSTunnelDetectTools
效果:

#!/usr/bin/env python
# -*- coding:utf-8 -*-


"""
DNS隧道通信檢測工具
作者:陳然
版本:V1.0.3
聯系:WeChat-Number -> cr1914518025
"""


#腳本信息配置:
_author  = "隱私保護"
_nicky   = "挖洞的土撥鼠"
_version = "v1.0.3"
_version_string = """\033[0;32m
            DNS隧道通信檢測工具
            作者:陳然
            版本:V1.0.3
            聯系:WeChat-Number -> cr1914518025
            操作系統:支持Linux、Unix、MacOS X、Windows
\033[0m"""

#引入依賴的庫文見、包
import os
import sys
import time
import pcap
import dpkt
import urllib
import logging
import platform
import datetime
from optparse import OptionParser


#配置全局設置
reload(sys)
sys.setdefaultencoding("utf-8")
logging.basicConfig(filename="./dnstunneldetect.running.log",level=logging.INFO,filemode='a',format='%(asctime)s-%(levelname)s:%(message)s')


#定義全局函數
def dns_request_analyst(string,sport):
    """解DNS請求報文"""
    logging.info("分析報文請求")
    dnsdata = dpkt.dns.DNS(string)
    ret = repr(string)#.replace("\\x03",".").replace("\\x05",".").replace("\\x12",".")
    domain = str(ret[41:-21])[3:]#.replace("")
    rtype = ret.replace("\\x","")[-9:][0:4]
    #print type(domain)
    domain = domain.replace("\\x",".")
    domainlist = domain.split(".")
    domain = domainlist[0]+"."
    for dstr in domainlist[1:]:
        dstr = dstr[2:]
        domain += str(dstr)+"."
    domain = domain[0:-1]
    score = float(len(domain) - 52.0) * 0.5
    if len(domain) <= 30:
        score = 0
    elif (len(domain) - 52) <= 0:
        score = (52 - len(domain)) * 0.2
    for item in list(str(domain)):
        if item not in list("01234567890-abcdefghijklmnopqrstuvwxyz."):
            score *= 2
            break
    if rtype == '0010':
        score *= 2
    else:
        score = score * 0.4
    pid = None
    if platform.platform().lower().find("windows") >= 0:
        pid = os.popen("netstat -ano | findstr %s"%sport).read().split("\n")[0].split(" ")[-1]
    elif platform.platform().lower().find("linux") >= 0:
        pid = os.popen("netstat -anop | grep %s | awk '{print $7}'"%sport).read().split("/")[0]
    elif platform.platform().lower().find("darwin") >= 0:
        pid = os.popen("lsof -nP | grep :%s | awk '{print $2}'"%sport).read().split("\n")
        for i in pid:
            if i != "['']":
                pid = i
                break
    else:
        pass
    flag = False
    if score > 4
    return True,domain,score,pid

#定義DNS嗅探解析報文獲取類
class Packet_Sniffer_Filter:
    """嗅探並過濾報文"""
    def __init__(self,iterfacename):
        """創建報文嗅探器"""
        logging.info("創建嗅探器")
        self.name = iterfacename#本機的嗅探網卡名稱
        self.sniffer = pcap.pcap(name=self.name,immediate=True)#設置嗅探器嗅探指定網卡
        self.sniffer.setfilter("udp port 53")#初步過濾
    def run(self):
        logging.info("嗅探器線程開始運行")
        for packet_time,packet_data in self.sniffer:
            packet = dpkt.ethernet.Ethernet(packet_data)#使用dpkt解pcap格式報文
            dip = tuple(map(ord,list(packet.data.dst)))#獲取目的IP地址
            dip = str(dip).replace(",",".").replace(" ","")[1:-1]
            sport = packet.data.data.sport
            dport = packet.data.data.dport
            if dport != 53:
                continue
            result_flag,domain,score,processid = dns_request_analyst(packet.data.data.data,sport)#加入待分析隊列
            if result_flag:
                print """\033[0;31m
                [*] 疑似DNS隧道通信
                    [-] 通信域名: %s
                    [-] 來源端口: %s
                    [-] 危險評分: %s
                    [-] 對端地址: %s
                    [-] 本地進程: %s
                \033[0m"""%(domain[3:],sport,score,dip,processid)



if __name__ == "__main__":
    logging.info("程序啟動")
    parser = OptionParser()
    parser.add_option("-i","--ifname",dest="name",help="Interface Name!")
    parser.add_option("-v","--version",dest="version",action="store_true",help="Show Version!")
    parser.add_option("-d","--docs",dest="docs",action="store_true",help="Show Documents!")
    parser.add_option("-r","--requirments",dest="reqr",action="store_true",help="Show Requriments!")
    (options, arges) = parser.parse_args()
    if options.version:
        print _version_string
        exit(0)
    if options.docs:
        print """\033[0;32m
            使用手冊--使用於V1.0.1版本
            [1] python DNSTunnelDetect.py -i eth1
        \033[0"""
        exit(0)
    if options.reqr:
        print """\033[0;32m
            [+] sudo pip install pypcap
            [+] sudo pip install dpkt
        \033[0"""
        exit(0)
    if options.name in ["",None]:
        logging.info("程序缺乏網卡參數,退出運行!")
        print "\033[0;31m[-] 請指定網卡\033[0m"
        exit(0)
    logging.info("程序初始化")
    PacketSniffer = Packet_Sniffer_Filter(options.name)
    PacketSniffer.run()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM