2021最新DGA恶意域名检测方法(附上Python代码)
近年来恶意程序的数量呈现逐年递增的趋势,并且越来越高级和复杂。由于域名系统在网络中都存在。并且通常不会被防火墙过滤,攻击者常用使用DNS来隐藏恶意行为,维护恶意网络自身的健壮。
恶意程序在感染了主机后,通常和远程的命令与控制服务器连接攻击者可以直接控制命令与控制服务器。如在高级持续性攻击和僵尸网络中,被感染的主机会通过远程的C&C服务器连接,下载最新的恶意程序或获取恶意命令;信息窃取等恶意程序会将窃取的信息发送给远程服务器等,拦截邮件依赖DNS重定向网页。这些恶意程序常通过域名来访问远程服务器,而不用服务器的IP地址,因而域名在恶意行为中发挥着重要的作用。
为了逃避检测,使得恶意网络更健壮,攻击者会采用domain-flux技术。
domain-flux 技术是指恶意程序采用域名生成算法 ( domain generationalgorithm,DGA) ,基于一个种子,如当前的日期,每天动态生成大量的域名,其中的一部分域名是被攻击者注册的有效域名,多个域名对应一个命令与控制服务器的 IP 地址。
DGA域名检测框架
如图所示,主要包括数据集获取、域名特征提取、DGA检测模型训练和域名检测4个部分。
1)获取数据集:分别获取正常域名和恶意域名数据集,作为已标记的数据集。
2)特征提取:从域名数据集中提取域名的特征。一类是域名字符的统计特征,如域名字符长度、字符随机性、唯一字符数、元音字母比例等; 另一类是域名的 N-Gram 模型特征。
3)训练 DGA域名检测模型:将训练数据集输入到机器学习模型当中进行模型训练。本文工作将采用多种检测模型,并对不同模型进行评估,对比检测效果的优劣。
4)域名检测:用训练好的模型对域名进行检测,检测出正常的或者恶意的 DGA 域名。
DGA恶意域名特征分析
域名特征提取是DGA域名检测的基础,特征选取的好坏直接影响DGA域名检测的效果,因此对正常域名和恶意域名的特征进行了分析和对比,以提取区分度大的特征组合。其中,域名字符的统计特征包括:域名字符长度、域名字符随机性、元音字母比例、唯一字符比例、顶级域名类型等。
1)域名字符长度发布如图所示,几乎所有的正常域名字符长度都在19以内,集中在8到12之间,只有少数域名到达了19以上。而恶意域名长度范围在8到32之间,并出现了2个高峰点,分别是12和30,其中长度为30的恶意域名数量更多。
2)字符随机性,由于恶意域名是DGA算法随机生成,其字符的随机性大,混乱程度较高,而正常域名字符的随机性较小。域名字符的随机性通过计算字符的熵来判断:H( d) = - ∑lg( P( Xi ) ) × P( Xi )
d 为域名; Xi 为 d 中的某一个字符; P( Xi ) 为该字符出现的概
3)元音字母比例分析,正常域名通常采用单词或名字的拼音,方便使用者记忆; 同时为了具有较好的可读性,正常域名往往会插入一定的元音字母,让域名读起来更顺口。恶意域名由于随机生成,不会考虑可读性,因而正常域名的元音字母的比例会比恶意域名的高。
4)唯一字符数,DGA域名有很大的随机性,其唯一字符会较高,唯一字符是域名中不同字符的个数,如域名baidu的唯一字符[b.a.i.d.u],字符数为5;域名urlzt.com唯一字符数有[u.r.l.z.t],字符为4。正常域名和恶意域名的唯一字符数分布情况如图所示。
5)唯一字符比例,计算域名中唯一字符数与域名长度的比值,正常域名和恶意域名的唯一字符,比例如图所示
6)顶级域名分析,正常域名的顶级域名一般会使用常见的顶级域名,如.cn和.com 等。恶意域名的顶级域名比较随意,攻击者会选择一些审核不严格的顶级域名,如.biz和.ru等。正常域名中其顶级域名数为 1933,其他为 67; 恶意域名中其顶级域名数为 1342,其他为 658。大部分正常域名的顶级域名都在常用顶级域名范围内,只有少数个别的没有在其中。恶意域名中有近 2 /3 的域名其顶级域名是常用顶级域名。
DGA域名检测方法
为了消除不同域名特征之间数据大小的影响,提取域名统计特征后,构建特征向量,并对特征向量进行标准化处理。
采用 z-score 标准化方法:
x' 为标准化后的数据; x 为原始数据; μ 为计算的平均值; σ 为标准差。处理后数据符合标准正态分布,即均值为 0,标准差为 1。对于域名的统计特征和 N-Gram 模型特征,分别使用机器学习算法进行 DGA 域名检测模型的训练。
DGA域名检测Python完整代码
#coding:utf-8
#The author:www.urlzt.com 域名检测-罗晶
import time
from scapy.all import *
from requests import *
conf.iface='Intel(R) Dual Band Wireless-AC 8260'
list=[]
dgalist = open('dga.txt','r')
dgalist = (dgalist.readlines())[18:]
for dga in dgalist :
list.append(dga.split('\t')[1])
data = set(list)
#Capture and Filter DGA
def capture(packet):
if packet:
i =0
for p in packet:
src = p[i][IP].src
dst = p[i][IP].dst
sport = p[i][UDP].sport
dport = p[i][UDP].dport
qr = str(p[i][DNS].qr)
rcode = str(p[i][DNS].rcode)
if '0' in qr:
qr = 'Query'
qname = p[i][DNS].qd.qname
if type(qname) == bytes:
qname = (qname.decode('utf-8'))[:-1]
if qname in data:
print("[*] Found DGA Request:-->",src,sport,qr,qname)
if '1' in qr:
if '0' in rcode:
for j in range(10):
try:
qr = 'Response'
rrname = p[j][DNS].an[j].rrname
rdata = p[j][DNS].an[j].rdata
if type(rrname) == bytes:
rrname = (rrname.decode('utf-8'))[:-1]
if type(rdata) == bytes:
rdata = (rdata.decode('utf-8'))[:-1]
if rrname in data:
print ("[*] Found DGA Response:-->",src,dst,qr,rrname,rdata,"\n")
except Exception as e:
pass
i = i + 1
#update dgafile
def dgafileupdate():
url = 'http://data.netlab.360.com/feeds/dga/dga.txt'
dgafile = get(url)
with open('./dga.txt','w') as f:
f.write(dgafile.text)
print('Download DGAFile Finished')
if __name__ == '__main__':
sniff(prn=capture,filter='udp port 53')
while True:
dgafileupdate()
time.sleep(86400)
- 点赞
- 收藏
- 关注作者
评论(0)