5 AI检测DNS缓存投毒攻击

5.1 安全问题

这个用例旨在展示深度学习在检测网络攻击方面的基本和经典应用。在这个用例中,所涉及的网络攻击是DNS缓存投毒攻击。

域名服务(DNS)的一个主要功能是提供域名与IP地址之间的映射。当用户计算机上的客户程序引用域名时,域名需要被转换为IP地址以进行网络通信。DNS服务器负责执行这种转换。 分布式的全球互联网DNS系统具有层次结构,包括根域名服务器、顶级域名服务器和权威域名服务器。一些例子是由Google提供的公共DNS服务器8.8.8.8和8.8.4.4,以及最近由Cloudflare发布的1.1.1.1。这些名称服务器被称为全球DNS服务器。由于用户计算机与全球DNS服务器之间的地理距离,每次需要某种映射信息时都与全球DNS服务器联系的成本非常高。为了降低成本,组织通常在局域网内部署自己的DNS服务器,称为本地DNS服务器,以缓存域名与IP地址之间最常用的映射。通常,当用户计算机需要与目标计算机建立连接时,它会首先联系本地DNS服务器以解析域名。如果本地DNS服务器没有缓存该域名的DNS记录,它将向全球DNS服务器发出DNS查询以获取用户计算机的答案。用户计算机在收到响应后得知IP地址。 DNS缓存投毒攻击可以针对本地DNS服务器。当本地DNS服务器接收到它没有相应记录的查询时(第一阶段),它将查询全球DNS服务器(第二阶段)。在收到响应(第三阶段)后,本地DNS服务器将此记录保存在其缓存中,并将响应转发给用户计算机(第四阶段)。然而,在第三阶段,DNS服务器无法验证响应,这就是攻击者可以欺骗本地DNS服务器的地方。攻击者可以假装是全球DNS服务器,向本地DNS服务器发送伪造的DNS响应,其中包含虚假的DNS记录。只要伪造的响应比真实响应先到达,本地DNS服务器将将其转发给用户计算机并将虚假记录保存到其缓存中,如图5.1所示。当关于相同域名的新查询进来时,本地DNS服务器将不会再次向全球DNS服务器发送查询,因为相应的记录已被缓存。因此,它将用虚假记录回答用户计算机,直到记录过期或缓存被清除。 DNS缓存投毒攻击难以使用传统方法(如基于签名和规则的入侵检测)检测,因为攻击者有意地制作其数据包以遵循协议,并使它们看起来非常类似于真正的DNS数据包。因此,有充分的动机将机器学习应用于检测这种攻击。然而,DNS缓存投毒攻击是一种基于会话的攻击。攻击数据包必须基于用户/服务器数据包进行制作,而攻击可能需要一个或多个攻击数据包。因此,每个数据样本需要包含来自多个数据包的信息,这使得特征工程成为一道艰巨的障碍。

在这个用例中,正如之前的工作所演示的[97],深度学习被应用来帮助跨越这个障碍。

5.2 原始数据生成和收集

在这个使用案例中,原始数据,包括良性和恶意数据,是由原始作者自己生成的,而不是来自现有的公共数据集,因为当时没有公共数据集提供DNS缓存投毒的网络数据包。有关详细信息,请参阅原始论文 [97]。作者利用协议模糊测试来突变网络数据包的内容,具体来说,是数据包中一些字段的值。使用协议模糊测试进行数据生成具有以下好处:1)通过协议模糊测试,可以以快速的速度生成大量选择的网络攻击的恶意网络数据包。2)由于网络数据包都是从选择的网络攻击中生成的,它们可以自动标记为恶意数据包,无需太多人工工作。3)协议模糊测试可以生成比真实世界数据更多变化的数据,甚至是尚未在真实世界中观察到的数据。4)协议模糊测试可以生成和覆盖可能在应用深度学习时被忽视的恶意数据样本,因为模糊字段的更改可能导致深度学习错误地将恶意数据样本分类为良性。通过协议模糊测试,如果恶意数据是在攻击中生成的,它们将被自动标记为恶意,因此它们不会被遗漏在恶意数据集中。此外,当利用协议模糊测试生成所需的良性网络数据包时,上述优点仍然存在。

应当注意的是,模糊测试是以不损害数据包和会话有效性为基础的。为了保持数据包级别的有效性,永远不会对影响数据包有效性的某些字段进行模糊,例如校验和值和数据包长度字段。这些字段的值不应该被随意更改。在模糊其他字段时,它们的值应始终在其有效范围内。例如,一个字节字段的最基本有效范围是 [0, 1, 2, . . . , 255]。为了保持会话级别的有效性,在选择要模糊的字段时,只选择能够保持攻击会话完整和成功的字段。

测试环境包含三台机器:一个本地DNS服务器、一个用户机器和一个攻击者机器。用户机器配置为与本地DNS服务器联系以解析域名。

在恶意场景中,用户机器要求本地DNS服务器使用dig命令为一个特定域名的IP地址。该域名在本地DNS服务器上没有相应的记录,从而启用了对其进行DNS缓存投毒的攻击。攻击者机器嗅探来自本地DNS服务器发送的具有该特定域名的DNS查询,然后用伪造的IP地址响应它们,伪造的DNS响应中包含虚假的IP地址。然后,DNS缓存被投毒,用户机器获得虚假的DNS记录。用户机器定期发送DNS查询,以便上述过程在很多次中发生,并且可以生成大量数据。然而,如前所述,如果本地DNS服务器在其缓存中具有域名的记录,它将不会为其发送DNS查询,这就是为什么定期刷新本地DNS服务器的DNS缓存的原因,以确保其在不同迭代中保持易受攻击状态。如果攻击成功,可以在dig的结果中看到伪造的IP地址。

在良性场景中,准备了一个包含4098个域名的列表。在每次迭代中,用户机器随机从列表中选择一个域名,并向本地DNS服务器请求其IP地址。为了模拟恶意场景,本地DNS服务器的缓存也定期刷新,以便本地DNS服务器总是需要与全球DNS服务器通信。

该使用案例使用网络流量数据,即网络日志。数据包捕获发生在受害者方,即本地DNS服务器。

表5.1显示了所捕获的DNS缓存投毒数据包的几个示例。所显示的所有数据包都来自一个DNS缓存投毒会话。192.168.100.128代表用户机器,192.168.100.50代表本地DNS服务器。数据包1显示用户机器向本地DNS服务器请求www.example.net的DNS记录;数据包2到5是本地DNS服务器发送到全球DNS服务器的查询数据包;数据包6是发送到本地DNS服务器的攻击数据包,其IP地址被伪装成全球DNS服务器的IP地址,且DNS记录也被伪造;数据包7是本地DNS服务器在(伪造的)响应从全球DNS服务器接收后,向用户机器发送的响应。

5.3 标记DNS会话

该使用案例的目标是训练一个深度学习模型,将DNS会话分类为“恶意”或“良性”。为了实现这一目标,需要一个带有标签的数据集。由于在先前的部分中已经收集了原始数据,本节将重点放在为收集的数据添加标签上。

这种攻击是基于会话的。每个会话,如表5.1所示,都由用户机器发送的DNS查询数据包标记。只有在攻击会话完成时才能生成恶意影响。因此,标签也是基于会话分配的:如果会话是成功的DNS缓存投毒攻击,则将该会话标记为恶意;否则,将该会话标记为良性。

幸运的是,这个使用案例中的恶意和良性原始数据已经被分开。恶意和良性数据是分开生成和收集的。良性原始数据不涉及恶意会话,而恶意原始数据不涉及未成功的攻击或良性会话。因此,在数据处理期间,可以分别处理和标记良性和恶意原始数据。

5.4 特征提取与数据样本表示

DNS缓存投毒攻击的网络数据包形成了由查询和答案组成的会话。因此,每个数据样本应包含来自多个网络数据包的信息。直观的想法是让一个数据样本包含会话中每个数据包中的每个字节。然而,这是一个不好的主意。一方面,如果没有任何特征提取,数据样本可能包含可能损害隐私的敏感私人信息,比如要查询的域。另一方面,模型可能会学到不希望学到的信息,比如机器的媒体访问控制(MAC)地址,这最好视为签名。

因此,与其使用整个数据包,不如选择来自每个DNS数据包的32个字节,如表5.2所列。最低的ETH层中的所有字节都被省略。这是有意排除的,以消除MAC地址的影响:MAC地址可能被视为检测恶意数据包的标志。选择的32个字节包括IP层、UDP层和DNS层的一部分。只使用DNS层的部分数据,因为查询和记录被排除在外。这些部分包含域名和IP地址,出于与上述相似的原因被排除:不希望神经网络学到“恶意”域名。在处理数据包数据后,每个数据包都被表示为一个包含32个整数的固定长度序列,整数范围从0到255。整个捕获的网络流量被表示为包含32个整数向量的序列,序列长度等于网络日志中的数据包数量。

既然整个网络日志可以被表示为包含32个整数的多个序列的长序列,下一步就是按会话切割整个日志(长序列)。具体来说,每当观察到来自用户机器的DNS查询数据包时,就在其前面切割序列。因此,可以生成多个变长序列,这里的序列长度等于一个会话中的数据包数量。

接下来的步骤是统一数据表示。具体而言,变长序列应该被处理成固定长度的序列。一般有两种方法可以做到这一点。一种是找到最长的序列,然后用虚拟数据填充所有其他较短的序列,使它们具有相同的长度。另一种方法是应用滑动窗口,以便长序列可以转换为若干较短的序列。在深度学习的多个场景中,这两种方法都被证明是有效的,在这个用例中,采用了滑动窗口方法。应用滑动窗口后,生成了多个固定长度的序列,这里的序列长度等于滑动窗口的长度。其中,每个元素都是一个包含32个整数的向量。

最后一步是改变整数。这些整数是从字节转换而来的,但整数可能不是字节的最合适的表示。例如,在DNS层的标志字段中有两个字节,但这两个字节由控制位组成。因此,接近的数字并不一定意味着所表示的功能是接近的。例如,在响应DNS数据包的情况下,DNS层标志字段的低字节(八位)包含五个控制标志:位0到3表示回复代码;位4表示是否接受非认证数据;位5表示答案是否经过身份验证;位6在响应DNS数据包中保留;位7表示是否可用递归。顺便说一句,0x00,其中所有位都为零,和0x10,其中除了位4外都为零,只在一位上有差异,但数字差异是16。简言之,比特表示在这种情况下可能更自然。相应地,向量中的整数被转换为比特。

最终,所有数据样本准备就绪,数据表示类似于具有三个维度的图像。第一维是数据包索引。第二维是数据包中的字节。第三维是字节中的比特。数据样本的相应标签也准备就绪:如果它来自攻击会话,则标记为恶意;否则标记为良性。整个过程如图5.2所示:

  1. 首先,整个网络日志按会话切割,其中一个会话包含七个数据包。

  2. 从这七个数据包中,选择感兴趣的字节(在这种情况下为32字节)。

  3. 然后,应用长度为6的滑动窗口,生成两个包含6个由32个整数组成的向量的序列。这样的序列也可以视为形状为6∗32的矩阵。

  4. 最后,将每个整数转换为比特。因为每个整数源自一个字节,8位足以表示所有整数。因此,生成的数据样本的形状为6 ∗ 32 ∗ 8,就像图像具有6行、32列和8个通道一样。

5.5 数据集构建

现在,数据样本和相应的标签准备就绪,下一步是构建训练集、测试集和验证集。然而,在将整个数据集拆分成它们之前,必须从整个数据集中排除两种类型的数据样本,因为它们无法帮助分类。

第一种被称为双重数据样本,指的是在多个类别中出现的相同数据样本。如图5.2所示,一个会话可能会产生一个或多个数据样本。因此,良性会话和恶意会话可能会生成相同的数据样本。这种数据样本是良性和恶意会话共享的,因此它们无法帮助分类。这就是为什么要从整个数据集中排除双重数据样本。

第二种是重复数据样本,指的是在同一类别中出现多次的数据样本。在这个用例中,重复数据样本指的是良性会话或恶意会话共享的数据样本。这样的数据样本应该在整个数据集中只出现一次,否则整个集合的数据变化性将受到损害。这就是为什么要从整个数据集中排除重复数据样本,以便它们在每个类别中只出现一次。

在排除双重和重复数据样本后,还有另一步是数据平衡。具体而言,如果数据集既平衡又足够大,则最理想。缺乏训练数据可能导致结果不佳,而有偏的数据集可能导致有偏的模型。处理后的数据集通常是不平衡的。为了减轻这种不平衡,一个常见的做法是对具有更多数据样本的进行降采样,但这会减小数据集的大小。为了应对这个困境,“平衡的数据集”标准被放宽:只要良性到恶意的比例在[ 2/3, 3/2 ]的范围内,就无需进行降采样。(这意味着良性和恶意都占整个数据的40%以上但不到60%,因此整个数据集是足够平衡的。)

在数据平衡后的最后一步是将数据集拆分为训练、测试和验证集。首先,从整个数据集中留出20%作为测试集,永远不会在训练中使用。其次,将整个数据集的其余80%进一步分为四个相同大小的折叠,然后应用4折交叉验证。

5.6 模型架构

由于数据样本类似于图像,因此选择了在计算机视觉领域已被证明对这种数据样本有效的卷积神经网络(CNN)。神经网络架构如图5.3所示。

5.7 参数调整

在这个用例中有两组参数。一组对应于滑动窗口,另一组对应于神经网络内部的超参数。

这组参数是关于滑动窗口的,包括窗口长度 w_size 和窗口步幅 w_step。窗口长度定义了滑动窗口的长度,窗口步幅定义了滑动窗口移动的大小。例如,在图5.2中,窗口大小为六,窗口步幅为一。对于 w_size,尝试了 {4, 6, 8, 10, 12};对于 w_step,尝试了 {1, 2, 4, 6, 8}。请注意,取决于第一组参数,数据集的大小可能会有所不同。

第二组参数是模型超参数,包括某些隐藏层中的单元数(卷积层1、2和全连接层,N_hidden ∈ {(C1 = 16, C2 = 16, F = 8), (C1 = 32, C2 = 16, F = 8), (C1 = 32, C2 = 32, F = 16), (C1 = 32, C2 = 32, F = 8), (C1 = 64, C2 = 32, F = 16), (C1 = 64, C2 = 64, F = 16)})、每个CNN层中的卷积核大小(K_size ∈ {(K1 = 2 * 2, K2 = 2 * 2), (K1 = 3 * 3, K2 = 3 * 3), (K1 = 4 * 4, K2 = 4 * 4)})以及在dropout层中的dropout率(D ∈ {0.05, 0.1, 0.15, 0.2, 0.25})。

代码5.5展示了如何构建分类神经网络。毫无疑问,第二组参数对于模型构建是必需的。第一组参数中的窗口大小也是模型构建所需的,因为它直接与输入数据样本的形状相关。

由于事先不知道哪些值会产生最佳结果,因此尝试了所有参数组合。而且,由于采用了4折交叉验证,总共训练了5 * 5 * 6 * 3 * 5 * 4 = 9000个模型。基于在所有四个折叠中对验证集的平均性能,选择最佳模型。

5.8 评估结果

表5.3显示了所选择模型的数据集统计信息,表5.4显示了评估结果。进行了四项测试指标,分别是准确度(Acc)、F1分数(F1)、检测率(DR)和精度(Pre)

5.9 模型部署

在模型训练和评估完成后,下一步是部署训练好的模型。然而,需要注意的是,训练环境与部署环境在几个方面存在差异。例如,生产系统通常具有不同的计算速度、内存/存储大小、网络带宽等。因此,生产系统更注重效率和成本,模型通常在部署之前需要进行额外的优化。

本用例中的神经网络使用TensorFlow 1进行训练,其中包含TensorFlow Lite 2,这是一组工具,通过帮助开发人员在移动设备、嵌入式设备和物联网设备上运行模型,实现了“在设备上进行机器学习”。它具有解决延迟(无需与服务器往返)、隐私(不会泄露个人数据)、连接性(无需互联网连接要求)、大小(减小模型和二进制大小)和功耗(高效推断和缺乏网络连接)等方面的优化。

在本用例中,采用了后训练量化(Code 5.6)。这是一种转换技术,可以在几乎不降低模型准确性的同时减小模型大小,并提高CPU和硬件加速器的延迟。后训练量化的最简单形式仅对权重进行静态量化,从浮点数转换为整数,具有8位精度。在推断期间,权重从8位精度转换为浮点数,并使用浮点内核进行计算。此转换只需进行一次,并被缓存以减少延迟。

为了进一步减小延迟,它基于激活的范围将激活动态量化为8位,并使用8位权重和激活进行计算。这种优化提供了接近完全固定点推断的延迟。然而,输出仍然使用浮点数存储,因此使用动态范围运算的加速效果小于完全固定点计算。

具体而言,在本用例中,后训练模型的大小可以从452 KB减小到41 KB,同时在训练集和测试集上评估指标(准确度、精度、检测率和F1分数)均未降级。

5.10 剩余的问题

关于这个用例,还有两个主要的问题。

  1. 运行时效率优化: 尽管已经通过后训练量化进行了初始的运行时优化,但另一个运行时效率优化的方面没有被考虑,即库依赖性。该模型是使用TensorFlow训练的,而TensorFlow本身依赖于许多其他库。因此,即使在推断时加载模型也会消耗相当多的资源。更糟糕的是,这个用例中的数据处理也需要大量资源。正如图5.2所示,原始网络数据包在生成数据样本之前需要经过四个步骤。在数据处理方面进行优化也是值得考虑的。

  2. 模型更新: 这个用例只涉及整个流程的一次迭代,从数据收集到模型部署。并未考虑更新模型。这在一定程度上是有道理的,因为训练的模型专门用于检测一种网络攻击。如果训练的模型已经能够很好地捕捉攻击的特征,那么更新模型的理由就很少了。然而,考虑到在部署之后观察到越来越多的数据,标记数据的规模正在增加。因此,在最简单的情况下,可以使用新数据重新训练整个模型,评估新模型,并将其与旧模型进行比较。如果新模型胜出,那么就可以用新模型替换旧模型。

5.11 代码和数据源

资源,包括部分原始数据、用于数据处理、模型训练、评估和运行时优化的脚本,都可以在本手册的GitHub存储库中找到,链接为 https://github.com/PSUCyberSecurityLab/AIforCybersecurity/tree/main/Chapter5-DL-for-Detecting-DNS-Cache-Poisoning。有关如何使用这些资源的详细说明,请参阅该存储库中的README.md。

Last updated