Press "Enter" to skip to content

DGA 域名检测的工程实践

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

 

引言

 

DGA(domain generate algorithm)是一种伪随机域名生成算法,可批量生成大量的伪随机域名,作为C&C(command and control server)域名,由于算法和参数可以预先确定,因此服务端可以利用同样的算法生成与客户端相同的域名。当攻击者需要对受害者机器进行操控时,可注册其中的一个或几个域名,受害者机器作为客户端,会定时尝试连接C&C服务器,一旦连接成功,恶意程序即可接受服务端指令,进行信息收集和恶意破坏等一系恶意活动。

 

传统的C&C域名检测方式是建立黑名单库,判断域名是否在黑名单内,然后决定是否连接该域名以及是否告警,从而检测和抵御某些远控木马。但是DGA算法一天内可以生成成千上万的域,因此我们不可能每天都重复收集和更新我们的黑名单库,并且黑名单库也难以检测未知的DGA域名。

 

传统的DGA攻击检测方式已经无法满足对不断变种的DGA域名的识别,难以适应DGA域名迅速增长带来的挑战,而机器学习算法在文本分类上的应用能够让我们训练出一个对数据有强大理解能力的模型,该模型可以快速有效地对大量DGA域名进行自动化识别。

 

DGA介绍

 

DGA技术的复杂性各不相同,有简单的统一生成的域名,也有试图在真实域中模拟分布的域名。总的来说可分为以下4种类型的DGA域名生成算法。

 

1)基于算术的DGA

 

根据时间或者随机种子,初始化出一系列可以根据ASCII码直接表示成域名的值,  或者使用这些值作为偏移量,指向DGA硬编码的字符表中的一个字符。目前网络上大部分的DGA域名都是由这种算法生成的。

 

2)基于哈希的DGA

 

使用十六进制表示的哈希值生成DGA域名,通常有SHA256和MD5两种哈希值。

 

3)基于单词表的DGA

 

从一个或者多个单词表中随机选择单词,并将其拼接成一个域名。

 

4)基于置换的DGA

 

对正常的域名进行置换操作,生成多个新的域名。

 

以下是github开源的一个比较简单的DGA算法banjori(https://github.com/baderj/domain_generation_algorithms/blob/master/banjori/dga.py):

 

step = 0 for m in key:      step += ord(m) for nr in range(10):      domain = ""      base += step      for i in range(length):          index = int(base/(3+2*i))          if i % 2 == 0:                 char = consonants[index % 20]          else:              char = vowels[index % 6]          domain += char domain += "." + tld print(domain)

 

程序可以通过length设置域名长度,可以通过设置key和base来设置生成伪随机字符串,从而生成大量的伪随机域名。同时控制端可以根据相同的key和base生成相同的域名列表。

 

当受害端被植入DGA远控木马后,会定时发起DNS查询,请求控制。而当攻击者需要上线该僵尸主机时,运行与僵尸主机相同的算法,生成大量域名,选择其中一个或者多个域名进行注册,然后攻击者将该注册域名指向C&C服务器。僵尸主机检测到该域名已经注册后,那幺远控木马就会连接到C&C服务器。如果当前域名检测未注册,那幺远控木马就将继续发起DNS查询。

 

LSTM算法

 

长短期记忆(LSTM)单位是递归神经网络(RNN)的单位。由LSTM单元组成的RNN通常称为LSTM网络(或仅称为LSTM)。公共LSTM单元由单元,输入门,输出门和忘记门组成。该单元记住任意时间间隔内的值,并且三个门控制进出单元的信息流。

 

 

LSTM网络非常适合基于时间序列数据进行分类,处理和预测,因为在时间序列中的重要事件之间可能存在未知持续时间的滞后。开发LSTM是为了处理在训练传统RNN时可能遇到的爆炸和消失的梯度问题。对于间隙长度的相对不敏感性是LSTM相对于RNN,隐马尔可夫模型和其他序列学习方法在许多应用中的优势。

 

所有递归神经网络都具有神经网络的链式重复模块。在标准的 RNN 中,这个重复模块具有非常简单的结构,例如只有单个 tanh 层。

 

LSTM 也具有这种类似的链式结构,但重复模块具有不同的结构。不是一个单独的神经网络层,而是四个,并且以非常特殊的方式进行交互。

 

 

首先,先熟悉以上使用符号。

 

 

在上面的图中,每行包含一个完整的向量,从一个节点的输出到其他节点的输入。粉色圆圈表示逐点运算,如向量加法;而黄色框表示学习的神经网络层。行合并表示串联,而分支表示其内容正在被复制,并且副本将转到不同的位置。

 

LSTM 的关键是细胞状态,即图中上方的水平线。

 

细胞状态有点像传送带。它贯穿整个链条,只有一些次要的线性交互作用。信息很容易以不变的方式流过。

 

 

LSTM 可以通过所谓“门”的精细结构向细胞状态添加或移除信息。门可以选择性地以让信息通过。它们由 S形神经网络层和逐点乘法运算组成。

 

RNN单元在面对长序列数据时,很容易便遭遇梯度弥散,使得RNN只具备短期记忆,即RNN面对长序列数据,仅可获取较近的序列的信息,而对较早期的序列不具备记忆功能,从而丢失信息。为此,为解决该类问题,便提出了LSTM结构,如图所示:

 

 

这里的tanh函数确保隐藏状态元素值在-1到1之间。
需要注意的是,当输出门近似1时,记忆细胞信息将传递到隐藏状态供输出层使用;
当输出门近似0时,记忆细胞信息只自己保留。

 

其核心关键在于:

 

1、提出了门机制:遗忘门、输入门、输出门;

 

遗忘门:决定什幺样的信息需要从单元中丢弃

 

输入门:决定输入中哪些值来更新记忆状态

 

输出门:根据输入和单元的内存决定输出什幺

 

2、细胞状态:在RNN中只有隐藏状态的传播,而在LSTM中,引入了细胞状态。

 

基于人工的域名特征提取和分析

 

笔者主要研究多种DGA域名生成算法,如Cryptolocker、Ramnit、Banjori、Pykspa等等。以这些算法为基础并调整参数,可以产生大量的DGA域名,同时还结合360 netlab(https://data.netlab.360.com/dga/)公开的dga域名库,总共生成了近80w的恶意域名。结合合法网站的80w域名。总共有160w的训练分析样本。

 

域名特征处理

 

在分析恶意域名基本特征和高级特征后,提取了域名的元音数、连续元音数、辅音数、连续辅音数、数字数、连续数字数、信息熵、n-gram处理后的排名特征、马尔科夫可读性得分等一系列特征参数。

 

1)信息熵分析

 

信息熵可以衡量一个域名的随机性,由于DGA域名基本是伪随机算法生成,那幺域名的混乱程度会较高。信息熵的计算公式如下:

 

 

其中,

P

i
表示域名中给定字符出现的概率。

 

计算信息熵的核心代码如下:

 

def cal_entropy(data):     import math     if not data:         return 0     valid_chars = set(data)          entropy = 0     for x in valid_chars:         p_x = float(data.count(x))/len(data)         if p_x > 0:             entropy += - p_x * math.log(p_x,2) return entropy

 

将所有样本统计计算后,结果如下图所示,正常域名的信息熵整体分布会靠左,也就是证明正常域名的随机性较低,因此根据该信息熵特征,域名具有一定的可区分性。

 

 

但仅依靠信息熵只能区分小部分的域名,还需要其他的特征进行补充,综合分析。

 

2)元音字母比重分析

 

正常网站的为了让用户方便记忆,通常会将域名设置成易读且容易被记住。因此正常域名中往往带有一定比例的元音字母,从而符合英文的发音习惯。而DGA域名具有随机生成的特性,且英文元音字母只有5个,因此在生成域名时元音字母所占比例会较低。计算元音字母比例的核心代码如下:

 

def cal_vowel(data):     '''     '''     vowel=['a','e','i','o','u']     valid_chars = set(data)     cnt = 0     if not data:         return 0     for char in data.lower():         if char in vowel:             cnt += 1 return float(cnt/len(data))

 

将所有样本统计计算后,结果如下图所示,DGA域名的元音字母占比分布靠左,也就是整体来看DGA域名中元音字母所占比例较低。

 

 

3)n-gram后的TF-IDF特征

 

主要使用的是1-gram、2-gram、3-gram特征,这些特征往往能反应域名字符的上下文特征。

 

1-gram的核心代码如下:

 

tv = TfidfVectorizer(ngram_range=(1,1),analyzer='char')
x = tv.fit_transform(X)
mean_all = np.mean(x.toarray(),axis = 1)
std_all = np.std(x.toarray(),axis = 1)
mean_all = list(mean_all.flat)
std_all = list(std_all.flat)

 

将所有样本统计计算后,结果如下图所示,分别展示了1-gram的tf-idf特征的均值和方差分布图:

 

 

可以看出均值具有一定的区分度。接下来再来看一看字符的排名特征:

 

 

可以看出1-gram的排名特征的均值也是具有一定的区分度。继续看2-gram,如下图:

 

 

具有一定的区分度,也是可以作为特征之一。

 

算法选取

 

笔者主要对比基于人工提取的特征向量的机器学习算法(随机森林、LightGBM)和深度学习算法(LSTM)之间的检测效率和性能。随机森林和LightGBM(Light Gradient Boosting Machine)是典型的集成学习算法,核心思路就是“人多力量大”,他们并没有创造出新的算法,而是把已有的算法进行结合,他们可融合多个简单模型,集成一个复杂模型,综合多个模型获得最有结果。在一定程度上可以有效的避免过拟合问题。

 

随机森林是典型的集成学习中的bagging算法,使用决策树作为基础模型,该模型得到的结果具有低方差的特点。bagging具体过程如下:

 

1、从原始样本集中抽取训练集。每轮从原始样本集中使用Bootstraping的方法抽取n个训练样本(在训练集中,有些样本可能被多次抽取到,而有些样本可能一次都没有被抽中)。共进行k轮抽取,得到k个训练集。(k个训练集之间是相互独立的)

 

2、每次使用一个训练集得到一个模型,k个训练集共得到k个模型。(注:这里并没有具体的分类算法或回归方法,我们可以根据具体问题采用不同的分类或回归方法,如决策树、感知器等)

 

3、对分类问题:将上步得到的k个模型采用投票的方式得到分类结果;对回归问题,计算上述模型的均值作为最后的结果。(所有模型的重要性相同)

 

LightGBM是改进后的boosting算法。是一款基于决策树算法的分布式梯度提升框架。为了满足工业界缩短模型计算时间的需求,LightGBM的设计思路主要是两点:

 

1、减小数据对内存的使用,保证单个机器在不牺牲速度的情况下,尽可能地用上更多的数据;

 

2、减小通信的代价,提升多机并行时的效率,实现在计算上的线性加速。

 

boosting的具体过程如下:

 

1、通过加法模型将基础模型进行线性的组合。

 

2、每一轮训练都提升那些错误率小的基础模型权重,同时减小错误率高的模型权重。

 

3、在每一轮改变训练数据的权值或概率分布,通过提高那些在前一轮被弱分类器分错样例的权值,减小前一轮分对样例的权值,来使得分类器对误分的数据有较好的效果。

 

LSTM算法在前文中已经介绍过,是一种时间序列的深度学习算法,传入的参数是域名序列信息,无需人工提取特征。

 

三种模型的查准率和查全率对比如下:

 

 

 

模型

 

 

最小值

 

 

最大值

 

 

平均值

 

 

随机森林

 

 

0.941

 

 

0.948

 

 

0.945

 

 

LightGBM

 

 

0.958

 

 

0.971

 

 

0.961

 

 

LSTM

 

 

0.973

 

 

0.990

 

 

0.986

 

 

查全率比较:

 

 

 

模型

 

 

最小值

 

 

最大值

 

 

平均值

 

 

随机森林

 

 

0.947

 

 

0.953

 

 

0.949

 

 

LightGBM

 

 

0.960

 

 

0.972

 

 

0.964

 

 

LSTM

 

 

0.976

 

 

0.989

 

 

0.985

 

 

由于随机森林和LightGBM算法需要输入域名的特征向量,实验结果强依赖于特征工程的处理结果,特征工程处理结果具有一定的差异性。而LSTM算法无需依赖特征工程,同时还能利用字符序列的上一个时间状态信息进行判断,在域名分类问题上具有较好的表现能力。
所以最终笔者采用LSTM算法进行实验。
步骤如下:

 

1、以样本为基础生成字符字典。

 

2、将每个域名对应字典进行映射,返回一个数字序列。

 

3、填充序列,将每个样本填充成等长的序列。

 

4、将序列输入到嵌入层(Embedding)。

 

5、将嵌入曾输入到调好参数的LSTM模型中,训练得到最终模型。

 

6、将模型持久化后,应用于后面的DGA域名检测。

 

实际运营中不断改进

 

虽然模型的误报率已经非常低了,但是在实际运营中会发现当DNS请求量非常大的时候,你总能遇到一些奇奇怪怪的域名。这时摸索DGA域名的原理,你可能会发现DGA远控木马大部分请求的一些无效域名,而且DGA域名请求有一定的时间规律,并且真中了DGA远控木马,一般不止请求一个DGA域名。所以需要我们在实际运营中不断改进我们的告警方式,不然巨量的告警真会让人头疼!

 

在这里笔者通过一段时间的运营后提出了几点建议:

 

1、当遇到同一个主机在某个时间段发起大量的疑似DGA域名请求时,需要关联IP的DNS请求的上下文信息,看是否每隔固定的时间发起同一批域名请求。如果是,则很可能中了DGA远控木马,需要上机排查。

 

2、当某主机发起一个疑似DGA域名请求,且该域名解析成功,返回IP地址,可以结合情报平台去确认该域名的标签。如未明确该IP的属性,则可简单排查该主机是否和返回IP地址之间存在长链接。

 

3、当某个主机在长时间不间断发起疑似DGA请求时,且大部分请求未解析成功,则需第一时间确定该主机的属性,也可通过抓包分析流量。如果是windows主机,则可通过sysmon追踪是哪个进程发起的请求。

 

4、在实际运营中也发现某些移动端会经常发起大量的疑似DGA域名请求,需要及时更新白名单,以免有效告警被噪声淹没。

 

DGA域名检测算法结合上安全运营工程师的经验才能发挥最好的效果。

 

作者

 

小舟,bilibili高级安全工程师,现负责b站安全运营和安全研究工作。

Be First to Comment

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注