基于深度卷积神经网络的 DGA 检测
- Published on
摘要
域名生成算法(DGA)是一种以确定但看似随机的方式生成域名的算法。恶意软件使用 DGA 来生成下一个访问命令与控制(C&C)通信服务器的域名。鉴于生成过程的简单性和域名生成的速度,需要一种快速准确的检测方法。卷积神经网络(CNN)在图像和视频识别等领域的实时检测方面表现出色,因此它们似乎适合用于 DGA 检测。本文对 CNN 在 DGA 检测中的性能进行了分析和比较。在包含 51 个 DGA 恶意软件家族和正常域名的数据集上评估了一个架构简单的 CNN。尽管架构简单,但最终的 CNN 模型正确检测出了超过97%的 DGA 域名,误报率接近0.7%。
1. 引言
域名生成算法(DGA)用于动态生成大量伪随机域名,然后选择其中一小部分用于命令与控制(C&C)通信通道。DGA 的动态特性旨在避免在恶意软件二进制文件中包含硬编码的域名,从而使逆向工程更难提取这些信息。最早的 DGA 检测尝试依赖于已被检测为 DGA 的域名的发布列表。然而,由于域名生成过程的简单性和速度,依赖静态域名黑名单的检测方法很快就失效了。
关于词法方法,自然语言处理(NLP)已成为检测 DGA 最有用的技术之一,特别是在分析域名的 n-gram 频率分布方面。n-gram被定义为给定文本序列中的n
个连续项目序列。可以使用大于 1 的n
值。在最简单的形式中,当n=1
时,生成单个字符频率分布。假设 DGA 域名的 n-gram 分布将与正常域名不同。n-gram 的 DGA 检测示例使用 Kullback-Leibler(K-L)散度比较一元和二元分布。
其他几种 DGA 检测方法扩展了使用域名属性(包括 n-gram 分布)来训练机器学习分类器(如随机森林或线性回归)的想法。最近,为了避免设计正确的特征集来训练机器学习分类器,一些作者探索了应用深度学习(DL)技术。特别是应用长短期记忆(LSTM)网络。当应用于文本分析问题时,LSTM 单元的内部设计能够捕获对区分 DGA 域名和非 DGA 域名很重要的字符组合。这种灵活的架构概括了像 n-gram 这样的手动特征提取,但是它学习字符的依赖关系,无论是连续的还是任意分隔的。
尽管报告的结果良好,但 LSTM 网络在某些特定情况下已被证明难以训练。上述问题以及训练所需的相当长时间可能是 LSTM 网络在 DGA 检测中大规模采用的主要障碍。事实是 DGA 技术随时间变化,网络的定期再演练变必要。然而,如果忽略 DGA 域名中长期依赖模式的存在,就可以应用另一种著名的深度学习技术:卷积神经网络(CNN)。CNN只是在其至少一个层中使用卷积代替一般矩阵乘法的神经网络。CNN 已成功应用于许多实际应用,主要与图像和视频识别相关。当应用于文本分析时,卷积应用于一个维度,称为 1D-CNN。1D-CNN 的主要优势是它们的训练速度比 LSTM 快得多(比 LSTM 快9X
)。1D-CNN 能够学习字符组的表示而无需明确告知此类组的存在。然而,它们无法处理具有任意分隔的模式。
在本文中,我们专注于分析 1D-CNN 的 DGA 检测性能。与之前的研究类似,我们有兴趣评估具有最小架构复杂性的网络的性能。因此,考虑的网络架构除了卷积层外只包含最少的额外层。评估在包含 51 个不同 DGA 家族的数据集上进行,以及来自 Alexa 语料库和 Bambenek feeds 的正常域名。数据集中包括两种不同的 DGA 方案,包括最近的基于词的方案。基于词的 DGA 包括连接来自一个或多个词表的一系列词,生成的域名看起来不那么随机,因此可能更难检测。
本文的主要贡献包括:
- 对简单 1D-CNN 学习模型在检测 DGA 方面的优势和局限性进行分析
- 在扩展数据集上对 1D-CNN 进行详细评估,该数据集包含来自 51 个不同真实恶意软件 DGA 的域名(遵循不同的生成方案)以及来自两个不同来源的正常域名
- 与另一种著名的深度学习技术进行比较。特别是之前已成功应用于 DGA 问题的 LSTM 网络。这最后一组实验为我们之前在该主题上的工作提供了重要补充
如今,DGA 检测方法可分为两大类:
- (A)基于上下文的方法
- (B)基于词法的方法
所谓的基于上下文的方法主要依赖于使用 DNS 服务器响应等上下文信息。一个典型的例子是 DGA 域名通常未注册,因此 DNS 响应通常是 NXDomain。另一方面,词法方法通过研究构成域名的字符的统计特性来分类域名。
2. 神经网络架构
本文使用的神经网络架构模型是一维 CNN。这个 CNN 由三个主要层组成。第一层是嵌入层,然后是一维卷积层,最后是密集全连接层。前两层是架构中最相关的组件,负责学习特征表示以输入到第三个密集全连接层。除了前面描述的三层外,完整的神经网络架构还包括一些用于处理 1D 卷积层输出维度的层,以及用于表示输入域名和输出概率的层。表 1 详细展示了完整架构及每层使用的激活函数,而三个主要层在以下小节中描述。
层 | 激活函数 |
---|---|
Input | - |
embedding (Embedding) | - |
conv1d (1D Convolutional) | ReLU |
dense1(Dense) | ReLU |
dense2(Dense) | Sigmoid |
2.1 嵌入层
字符嵌入将长度为l
的输入字符序列投影到向量序列中,其中:
l
需要从训练集中的序列信息确定d
是表示结果矩阵维度的自由参数
通过在架构中使用嵌入层,神经网络可以有效地学习表示输入数据的最优特征集。
2.2 一维卷积层
一维卷积层指的是在一个维度上的卷积网络层。对于 DGA 检测问题,该维度由域名序列的长度组成。卷积层由一组应用于域名不同部分的卷积滤波器组成。图 1 展示了一维卷积层特征提取过程的可视化示例。该图描绘了一个 1D 卷积层构建 256 个滤波器(特征)(nf=256),窗口(核)大小为 4(ks=4),步长值为 1(sl=1)。该层从 4 个字符的组(也称为 patches)开始应用卷积滤波器,并继续每次移动一个字符(步长值)对序列的其余部分应用相同的卷积滤波器。因此,神经网络生成 4-gram 特征。这些特征代表了域名中这些字母组的判别能力。
通过在整个序列上应用相同的滤波器,与传统的多层感知器层相比,所需的计算时间大大减少。此外,由于卷积核独立地对每个 4-gram 进行操作,因此可以同时处理整个输入层。这种并行化及其带来的低计算时间是使用卷积网络而不是其他通常用于文本处理的深度学习方法(如长短期记忆(LSTM))的主要优势之一。
主要参数包括:
nf = 256
(滤波器数量)ks = 4
(窗口大小)sl = 1
(步长值)

2.3 全连接层
前两层提取的特征被传统的多层感知器网络(MLP)使用,输出给定域名属于 DGA 或正常类的概率。MLP 由两层组成:
- 大小为
hn
的第一个全连接层(Dense 层) - 大小为 1 的第二个 Dense 层,用于实际给出域名的概率输出
3. 实验设计
本节描述用于评估 1D-CNN 检测性能的实验设计。我们从两个角度关注算法的检测性能。首先,考虑 DGA 和正常域名的检测。其次,考虑数据集中不同恶意软件家族的检测性能。
我们使用了几个标准的网络检测评估指标。特别是真阳性率(TPR)和误报率(FPR)。TPR 定义为正确检测的 DGA 域名数量与 DGA 域名总数的比率。FPR 定义为错误分类为 DGA 的正常域名数量与正常域名总数的比率。此外,我们还使用了准确度(ACC)和 F1 分数等其他标准指标。
1D-CNN DGA 检测方法的评估遵循常规的机器学习方法论。包含 DGA 和正常域名的数据集按照 70%/30%的比例进行划分。为了保证结果的独立性,数据集的 70%用于调整 1D-CNN 的超参数(训练集)。而剩余的 30%(测试集)用于测试 1D-CNN DGA 检测模型在未见域名上的性能。
3.1 数据集描述
1D-CNN 检测方法在包含 DGA 和正常域名的数据集上进行评估。正常域名来自两个不同来源:
- Alexa 排名: 包含排名前一百万的域名
- Bambenek Consulting feed: 包含 3,161 个正常域名。这些域名特别有趣,因为它们包含了一些可疑但不是由 DGA 生成的域名
因此,数据集中正常域名的总数为1,003,161个。DGA 域名来自两个主要来源:
- Bambenek DGA Feed: 包含活跃 DGA 的域名
- Andrey Abakumov 收集: 包含已知 DGA 的域名
DGA 域名总数为1,915,335个,它们属于 51 个不同的恶意软件家族。这些家族使用不同的生成方案,从简单的算术计算到更复杂的基于词的方案。

恶意软件家族使用的 DGA 生成方案包括:
- 简单算术(A)方案
- 最新的基于词(W)方案
在算术方案下,算法通常计算一系列可用于域名的 ASCII 表示值。这些值可能来自简单的数学运算,如加法、乘法或位运算。而基于词的方案则是从一个或多个预定义的词表中选择并连接一系列词。这种方法生成的域名通常看起来更像合法域名。
3.2 超参数调优
调整网络超参数可能是神经网络应用中最困难的任务之一。对于提出的 1D-CNN 架构,需要调整几个关键超参数。我们特别关注与三个主要层相关的参数:嵌入层、Conv1D 层和 Dense 层。这些参数的选择对模型的性能有重要影响。
嵌入层参数:
l
: 输入序列长度d
: 矩阵维度
对于嵌入层,需要设置两个值:l
和d
。参数l
是输入序列的长度。该参数通过遵循常见方法设置为数据集中发现的最大域名长度。因此,只需要调整矩阵维度d
。
Conv1D 层参数:
nf
: 滤波器数量ks
: 核大小sl
: 步长(固定为 1)
Dense 层参数:
hn
: 神经元数量thres
: 决策边界阈值(设为 0.90)
在第一个 Dense 层中需要优化神经元数量hn
。最后,由于 DGA 检测模型要求低误报率,第二个 Dense 层的决策边界阈值(thres
)设置为 0.90,而不是更常见的 0.5。因此,只有那些具有很高概率的域名才会被检测为 DGA。
avg. F1 | sd | nf | ks | sl | d | l | hn | Parameters |
---|---|---|---|---|---|---|---|---|
0.9797 | 0.0050 | 256 | 4 | 1 | 100 | 45 | 512 | 5,612,705 |
表3. 提出架构的最佳超参数。仅显示第一个参数组合。选择具有更高平均F1-Score的参数组合用于后续实验。
在训练集的指定子集上进行了传统的网格搜索。为了进行稳健的估计,每个参数组合的评估都使用了k=10
折交叉验证进行。1D-CNN 层使用反向传播算法进行训练,考虑了自适应矩估计优化器。1D-CNN 的训练持续了 10 个 epoch。
表 3 显示了在 F1-Score 方面具有更好检测性能的参数组合。
3.3 未见域名的评估
为了评估模型对未见域名的泛化能力,我们在独立的测试集上进行了评估。这个测试集包含了训练过程中从未见过的域名。评估结果显示,1D-CNN 模型表现出色:
- TPR:
~97%
(DGA 域名检测率) - FPR:
~0.7%
(误报率) - ACC:
98.3%
(总体准确率) - F1:
0.97
(F1 分数)
对于正常域名类型的 FPR 区分:
- Alexa 域名: 几乎 100%正确检测为正常
- Bambenek 域名: 误报率增加到 16%

图 2 显示了每个 DGA 恶意软件家族的 TPR 及其 DGA 生成方案(红色表示算术型,蓝色表示基于词)。圆圈周围的直径提供了该恶意软件家族在训练集中 DNS 请求绝对频率的视觉提示。总的来说,大多数 DGA 都被检测到,无论使用什么 DGA 生成方案,TPR 都接近 0.75。唯一的三个例外是 Cryptowall(TPR 值为 0.16)、Virut(0.39)和 Suppobox 恶意软件(0.47)。
这些结果表明,模型在处理来自不同来源的域名时表现出不同的特征。特别是对于 Bambenek feed 中的可疑但合法的域名,模型表现出较高的误报率,这反映了这类域名与 DGA 生成的域名在特征上的相似性。
4. 讨论与分析
根据我们的实验结果,1D-CNN 检测方法展现出了提取不同恶意软件家族中算术型 DGA 生成算法共同模式的能力。这一发现可以解释为什么在一些样本频率极低的恶意软件家族中也能获得令人满意的结果。例如,像 chinad 和 bamital 这样的家族,尽管在数据集中的样本数量不足 1000 个,但其 TPR 值仍然能够超过 90%。
然而,对于基于词的 DGA 方案,情况则明显不同。从图 2 的右侧箱线图可以看出,75%的算术型 DGA 的 TPR 值集中在 1 到 0.92 之间。比之下,基于词的 DGA 方案中,75%的 TPR 值分布在 1 到 0.70 之间。这些结果清楚地表明,使用算术型生成方案的恶意软件家族的检测性能显著优于使用基于词生成方案的家族。这种性能差异可能源于基于词的生成方案试图模仿正常域名的特征。
然而,我们观察到了一些需要深入分析的意外结果。特别值得注意的是 Matsnu 恶意软件家族(一个基于词的 DGA)达到了 0.92 的 TPR,而 Virut(一个算术型 DGA)仅获得了 0.39 的 TPR。
对于 Virut 的情况,其较差的性能可以通过分析其生成的 DGA 域名的字符频率分布(FCD)来解释。图 3 展示了 Virut DGA 恶意软件的 FCD(黑色)与正常域名的 FCD(白色)的对比。值得注意的是,为了便于比较,我们只在正常域名的 FCD 中包含了出现在 DGA 域名中的字符。

尽管 Virut 不是基于词的 DGA,但其元音字母的频率相对于其他字符明显较高。更重要的是,这种元音频率分布与正常域名的 FCD 表现出相似性。这种与正常 FCD 的相似性可能增加了 1D-CNN 检测方法的识别难度。考虑到 Virut 在数据集中的样本数量较少,这个问题变得更加突出。
对于 Matsnu 的情况,其较高的 TPR 无法通过 FCD 来解释,因为正如预期的那样,Matsnu 的 FCD 与正常域名的 FCD 具有相似性。在检查了 DGA 的几个方面后,我们发现域名长度是区分正常域名和 Matsnu 域名的判别特征。Matsnu 生成的域名明显长于正常域名。图 4 对比了 Matsnu 和正常域名的字符长度分布(CLD)。如图所示,Matsnu 域名明显长于正常域名。另一方面,suppobox 恶意软件(如图 4 所示)的 CLD 接近正常域名。由于不仅 CLD 而且 FCD 都与正常域名相似,suppobox 域名变得非常难以检测。

5. 基于 LSTM 网络的 DGA 检测对比分析
本节将对比使用简单 LSTM 网络和前文描述的 1D-CNN 进行 DGA 检测的性能。特别地,LSTM 网络架构按照 Woodbridge 等人的描述实现。长短期记忆(LSTM)网络是一种特殊类型的循环神经网络(RNN),由 Hochreiter & Schmidhuber 在 1997 年首次提出,在自然语言处理(NLP)问题上取得了成功。与卷积网络和密集连接网络相比,LSTM 的主要优势在于每个输入都需要独立处理,输入之间不保持状态。这种缺乏记忆的特性使得处理序列或时间序列数据变得复杂。另一方面,LSTM 能够记住序列中之前看到的信息。这种能力转化为学习不一定在序列中连续的字符模式。这种能力以及与 1D-CNN 的模式差异可以在图 5 中观察到。

与卷积网络类似,LSTM 网络必须包含至少一层 LSTM 单元。LSTM 单元由一个可以通过一组可编程门操作的状态组成,这些门允许单元记住或遗忘特定输入。额外的输出门调节单元状态对输出的贡献,该输出传播到整个层的 LSTM 单元的输入门以及后续层。
在本例中,神经网络架构由一个嵌入层和一个 LSTM 层组成。最后,在输出层之前添加了一个 Dropout 层。Dropout 包括在训练期间随机移除网络层之间的随机子集边缘,但在测试时恢复它们的贡献。LSTM 网络的详细架构如表 4 所示。
层 | 激活函数 |
---|---|
Input | - |
embedding (Embedding) | - |
lstm (LSTM) | ReLU |
dropout 1 (Dropout) | - |
dense2(Dense) | Sigmoid |
嵌入层的网络超参数设置为d=128
和l=75
,而 LSTM 层中的 LSTM 单元数量设置为 128。最后,Dropout 层设置为 0.5。与 1D-CNN 类似,LSTM 网络在数据集 70%的部分上训练了 10 个 epoch,并在剩余 30%上进行测试。
最终模型在数据集中总 DGA 的检测率(TPR)约为 94%,而总正常域名的误报率(FPR)接近 3%。根据之前的结果,LSTM 网络的性能明显低于 1D-CNN,特别是考虑到在实际场景中低误报率的重要性。

图 6 显示了每个 DGA 恶意软件家族的 TPR 及其 DGA 生成方案。与图 2 类似,大多数 DGA 的 TPR 值接近 0.75。此外,如图 6 右侧的箱线图所示,75%的算术型 DGA 的 TPR 集中在 1 到 0.92 之间。然而,基于词的方案的 75%TPR 值分布在 0.97 到 0.12 之间,这比 1D-CNN 的结果要差得多。

图 7 显示了包含恶意软件家族和正常请求在内的详细比较。如图所示,LSTM 在处理 Cryptowall(基于词的 DGA)和 Virut 恶意软件时的性能优于 1D-CNN。另一方面,1D-CNN 在大多数基于词的 DGA(如 Beebone、Suppobox、Matsnu、Madmax 和 Volatile)的检测方面显著优于 LSTM。这种在基于词的 DGA 检测方面的低性能也在实验中被观察到。
重要的是要记住,论文中提出的 LSTM 架构比第 2 节描述的 1D-CNN 更简单。此外,1D-CNN 中存在的额外 Dense 层可能是 LSTM 网络在基于词的检测性能较差的原因。
6. 结论与展望
本研究探索了一维卷积神经网络(1D-CNN)在词法 DGA 检测中的可行性。一个具有最小架构复杂性的网络在包含 51 个不同恶意软件家族生成的域名以及正常域名的数据集上进行了评估。恶意软件家族包括两种不同的 DGA 生成方案:(1)最常见的基于算术的方案和(2)最新的且更难检测的基于词的方案。数据集适当地分为训练集和测试集。在训练集上进行了超参数网格搜索,然后在测试集上评估了最佳结果模型。
尽管架构简单,但最终的 1D-CNN 模型正确检测出了超过 97%的 DGA 域名,FPR 约为 0.7%。这样的结果使其适用于实际网络。检查恶意软件家族的结果,我们观察到 75%的基于算术的 DGA 的 TPR 值在 1 到 0.92 之间。即使在样本频率低的恶意软件家族中也观察到这样的值,证实了 1D-CNN 可以学习不同 DGA 生成家族的共同特性的假设,至少在基于算术的生成方案下是这样。另一方面,在基于词的方案中,75%的 TPR 值分布在 1 到 0.70 之间。TPR 结果的这种高度变异性反映了像 Matsnu 这样的恶意软件的高 TPR 和像 Suppobox 和 Cryptowall 这样的恶意软件的低 TPR。通过分析 FCD 和 CLD,我们发现尽管两者都与正常域名共享 FCD,但 Matsnu 在域名长度上显示出显著增加,这种情况使其容易被检测。与此不同的是像 Suppobox 这样的恶意软件,它与正常域名共享 FCD 和 CLD,因此很难被检测。
将 1D-CNN 与简单 LSTM 网络在相同数据集上进行了性能比较。实验表明,就 TPR 和 FPR 而言,LSTM 的性能比 1D-CNN 差。特别是,LSTM 获得的 4%的误报率是一个显著的性能损失,在应用到实际网络时影响很大。这种性能损失可能可以通过 Woodbridge 等人提出的 LSTM 架构过于简单来解释。具有更复杂架构的 LSTM 网络的性能将是未来工作的主题。
尽管 1D-CNN 显示出良好的结果,但我们观察到对于那些与正常域名共享 CLD 和 FCD 的基于词的 DGA 来说,检测可能非常困难。因此,随着基于词的生成方案在模仿正常域名方面变得更加精确,检测可能变得极其困难。此外,这些特殊情况可能超出了仅基于词法方法的检测能力范围。因此,可能需要替代的检测策略。
参考文献
Deep Convolutional Neural Networks for DGA Detection
示例代码
import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Input, Embedding, Conv1D, Flatten, Dense
from tensorflow.keras.models import Model
# 定义有效字符和映射
VALID_CHARACTERS = "$abcdefghijklmnopqrstuvwxyz0123456789-_."
CHAR_TO_INDEX = {char: idx for idx, char in enumerate(VALID_CHARACTERS)}
# 域名编码函数
def encode_domain(domain, max_len):
encoded = [CHAR_TO_INDEX.get(char, 0) for char in domain.lower()]
# 填充或截断到固定长度
if len(encoded) < max_len:
encoded += [0] * (max_len - len(encoded))
else:
encoded = encoded[:max_len]
return np.array(encoded)
# 构建模型函数
def build_model(input_length, vocab_size, embedding_dim, num_filters, kernel_size, hidden_size):
inputs = Input(shape=(input_length,))
embedding = Embedding(input_dim=vocab_size, output_dim=embedding_dim, input_length=input_length)(inputs)
conv = Conv1D(filters=num_filters, kernel_size=kernel_size, activation='relu', padding='valid')(embedding)
flat = Flatten()(conv)
dense1 = Dense(hidden_size, activation='relu')(flat)
outputs = Dense(1, activation='sigmoid')(dense1)
model = Model(inputs=inputs, outputs=outputs)
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
return model
# 参数设置
MAX_LEN = 45 # 域名最大长度
VOCAB_SIZE = len(VALID_CHARACTERS)
EMBEDDING_DIM = 100
NUM_FILTERS = 256
KERNEL_SIZE = 4
HIDDEN_SIZE = 256
# 构建模型
model = build_model(
input_length=MAX_LEN,
vocab_size=VOCAB_SIZE,
embedding_dim=EMBEDDING_DIM,
num_filters=NUM_FILTERS,
kernel_size=KERNEL_SIZE,
hidden_size=HIDDEN_SIZE
)
model.summary()
# 示例域名输入
def prepare_input(domain):
encoded_domain = encode_domain(domain, MAX_LEN)
return np.expand_dims(encoded_domain, axis=0) # 增加批次维度
# 示例
sample_domain = "example-domain.com"
input_data = prepare_input(sample_domain)
# 模型预测
prediction = model.predict(input_data)
print(f"Prediction: {prediction}")