X

智能模糊测试「测试技术1」

变异测试也可以归为模糊测试,因为模糊测试的数据产生有两种类型:

  • 基于变异的模糊器对有效的输入进行变异而生成一个输入集合;
  • 基于生成的模糊器分析所提供的有效输入结构,并生成全新的数据。

第一种类型其实可以归为变异测试,即变异测试是模糊测试的一种类型。

模糊测试的概念,去年年底在 2021年软件测试工具总结——模糊测试工具 已经有交代,包括什么是模糊测试,以及目前主要的三种模糊测试技术(黑盒随机模糊、基于语法的模糊和白盒模糊处理),模糊测试属于动态测试,是一种自动发现软件安全漏洞的经济有效的测试技术,常常会在软件安全开发生命周期中发现非常严重的安全故障或缺陷,例如:崩溃、内存泄漏,未处理的异常等,而且模糊测试有助于发现传统测试方法或手动审计无法检测到的缺陷。

今天我们侧重讨论智能的模糊测试技术,然后利用这种技术对机器学习应用进行测试。

1. 智能模糊测试

智能模糊控制器将允许开发人员或研究人员探索更多的应用程序,并有可能找到以前未发现的错误。这种 “智能 “来自于在模糊控制器中内置的一些通用智能,例如:

  • 输入格式是怎样的?
  • 上一次的输入是否比上一次的输入引起了进一步的代码覆盖?
  • 可以对输入进行哪些修改以探索进一步的代码覆盖?

如果模糊器能够确认这三个因素,那么为应用程序生成的输入类型将更多地针对特定的应用程序进行有效性的设计,比传统的模糊测试能更快找到bug。

一般来说,智能模糊器会使用不同类型的算法来生成这些任意的输入,而不是简单地使用绝对随机输入的方法。智能模糊器常采用的方法有:

  • 模板/语法模糊法:基于手动生成的模板的模糊测试,通常由模糊测试工具的开发商提供, 适用于有协议或特定结构输入的应用程序。如Peach Fuzzer可以建立状态模型和数据模型,设置监控器,根据状态来调整数据生成策略。
  • 指导性模糊测试:模糊应用程序观察目标应用程序状态的变化,然后利用这些知识来生成下一个输入。可以引入符号执行的方法,指导下一个输入的生成。
  • 基于变异的模糊测试:输入通过变异技术进行修改,如比特翻转、交换字节、删除字节,或对先前的输入或种子进行其他奇怪的修改。
  • 基于进化的模糊处理:这是引导式模糊方法和基于变异的模糊方法的结合。可以引入遗传算法等,最初的输入是通过种子创建的,然后随着时间的推移,通过变异算子进行迭代,测试能力越来越强大。

每种技术都有其优点和缺点,而且可能不适合每一种用例。这方面的应用越来越多,如:

  • Microsoft的研究团队在2008年就将模糊分析和符号执行结合起来,研究出具有智能模糊测试策略的工具SAGE,这是标志性的工作,将模糊测试带入智能的时代。SAGE记录执行情况并以符号方式评估跟踪,以收集新的约束条件,使用约束求解器产生新的输入,以执行新的控制路径,然后度量代码覆盖率,对达到最大测试深度的新输入进行排序(详见:SAGE: Whitebox Fuzzing for Security Testing)。
  • 新加坡管理大学研究团队的SmartFuzz将组合测试生成与轻量级程序分析相结合,其目的在于以高效、自动化的方式提高组合测试覆盖率(SmartFuzz: An Automated Smart Fuzzing Approach for Testing SmartThings Apps,2020 27th APSEC)。
  • Google有一个在Cloud中运行的智能模糊测试工具oss-fuzz(详见:https://google.github.io/oss-fuzz/)
  • 苹果公司在iOS10中使用了LLVM技术(可以使用libFuzzer,详见using LLVM’s libFuzzer with Swift),可以分析App Store中应用程序的字节码或者位码,通过LLVM轻松的分析这些应用程序,从而找到最基础的安全漏洞,如API滥用和隐私泄漏等。

2. 智能模糊测试的基本原理

为了进行有效的模糊测试,智能模糊控制器能够执行下列任务:

  1. 产生新的种子
  2. 启动目标程序(通过Harness或单独的程序)。
  3. 为目标程序提供一个测试用例
  4. 确定一个给定的用例是否提供了新的代码覆盖率
  5. 变异/进化能带来正回报的输入
  6. 检测程序是否崩溃或停顿

在这个过程中,种子数据可以由用户提供,但智能测试工具能够比较、分析哪些种子提供了更高的代码覆盖率。对于每个提供新代码覆盖率的测试用例,使用选定的变异方法/策略对其进行修改。当执行基于语法/模板的模糊处理时,确保它符合模板的要求。然后,将这些新的测试用例添加到测试用例队列中,以便模糊测试工具执行应用程序。导致崩溃的输入会被重新定位到一个与其他种子分开的文件夹中,因此用户知道是哪个输入导致了这个意外的行为。

模糊化框架(Harness)的开发是为了弥补模糊器期望的输入方式和应用中实际的输入方式之间的差异。借助模糊化框架,可以将来自模糊器的输入正确地转化、传递给模糊目标,从而使目标能够像任何正常的交互一样处理输入。

示例:AFLSmart工具的输入模型mp3.xml

3. 针对机器学习算法进行模糊测试

如果模糊测试的核心部分是找到有问题的输入,那么关键问题就变成:我们如何去实际找到这些导致系统行为失常的新输入?

第一个想法,自然是使用完全随机的搜索,例如通过随机修改像素值来产生输入,直到机器学习(ML)系统输出错误结果。但这种想法有几个缺点。首先,其效率很低,因为找到相关的故障案例可能很困难,而且计算成本很高。其次,怎么知道“ML系统输出错误结果”,因为ML系统出错和安全性测试不一样,系统不会崩溃,但其实结果已经出错了。例如,ML系统把图像中的狗判定为一只猫,而不会引起任何警报。最后,在应用程序的上下文中,输入可能很快变得没有语义,从而超出了系统预期的良好表现。对这样的输入进行测试可能会很有趣,例如,接触不良可能会导致随机的图像,这时我们仍然希望系统能优雅地失败。

(添加合成雾会导致对现场ML系统是否需要维护检查的判断产生重大影响)

在我们继续之前,让我们看一下如何评估系统是否真的在失效。这些是对输入图像的变化,以一种可预测的方式改变已知的标签。例如,分类问题的输出往往不应取决于图像的旋转方式:旋转后的狗仍然是一只狗。

这个概念奠定了针对ML系统进行模糊测试的基础。只要通过某种操作修改输入,引起ML算法的误解,预测结果与标签不一样,我们就可以确定一个新的输入 “破坏 “了系统。

为了成功应用模糊测试,我们需要比完全随机搜索更有效率的方法。大多数方法都是基于根据一组指定的规则和操作来变异初始输入的想法。例如,DLFuzz(“DLFuzz: Differential Fuzzing Testing of Deep Learning Systems”,Guo et al.,arXiv.org, 2018.)着重于这样的想法:由于训练过的系统中神经元覆盖率低,有问题的输入往往会出现。在训练过程中没有被激活的大量神经元子集,可能被新图像激活而导致意外的预测结果。DLFuzz修改输入图像以激活这些很少被访问的神经元,从而触发这类故障。

另一种方法,DeepHunter(“DeepHunter: A Coverage-Guided Fuzz Testing Framework for Deep Neural Networks”, Xie et al., ISSTA, 2019)在保留了图像标签的集合中选择一组随机变换,这样一来,新生成的模糊输入是否会降低ML的性能,可以用原来的图像标签进行评估。事实上,如果我们通过随机旋转来修改一幅图像,并期望标签保持不变,我们可以将系统对新旋转图像的输出与原始图像标签进行比较,以判断ML的预测是否正确。

4. 如何利用模糊测试来测试ML系统?

在实践中,模糊测试是测试ML系统的重要技术之一。它允许我们对系统进行压力测试,通过利用更大的合成数据集,可以包含那些实际中可能出现但不在原始数据集中的图像,这样我们更清楚地了解ML系统的实际表现。

假设我们正在为一个机器人建立一个系统,这个机器人被设计用来调查一个可再生能源的网站。在建立这样的系统时,数据的可用性往往成为一个核心挑战。虽然我们可能有足够的在雨天拍摄的一般图像,以及在晴天拍摄的风力涡轮机的图像,但雨天的涡轮机图像可能很稀少。对于复杂的现实世界的系统,往往不可能对实践中出现的所有情况都有足够的覆盖。因此,数据扩增技术是构建计算机视觉系统的关键和标准的可用技术。

模糊测试可以在系统的运行环境中对其进行压力测试,以找到系统表现较弱的组合,以及应该进一步增强或收集新数据的地方。例如,在上面机器人测试的例子中,我们可以通过以下方式产生模糊输入:

  • 在强度为x的图像上添加随机的合成雾气。
  • 在位置p处添加强度为y的随机强光。

可以通过这些变换进行模糊变异来产生大量的输入图像,以寻找故障案例。这个过程非常强大,因为它可以提供大量在实践中可能出现但在现有数据集中不存在的图像。在DeepHunter中可以找到更多关于如何通过引导的方法来完成的灵感。通过在整个开发过程中反复运行这样的测试,团队可以确保ML系统按照预期工作,并且可以发现需要进一步增加数据和收集数据的问题案例。

模糊测试还可以帮助回答一个更广泛的问题:当系统遇到 “意外 “的图像(不在其运行环境考虑之内)时,是否表现良好?开发团队应确保系统在这种情况下能优雅地失败。

一个典型的神经网络的复杂性使它容易受到各种故障的影响,包括在像素空间上与系统表现良好的图像相近的图像上出现故障。这一点在对抗性例子领域已经有了广泛的研究。

(从“Explaining and Harnessing Adversarial Examples‘”中,在加入小的噪声后网络性能发生了巨大的变化,可信度从 57.7%提高到99.3%。)

模糊测试也可以用于ML系统的冒烟测试,例如测试系统在部分变黑的图像和其他此类变换中的表现。一些开源的库(如“Albumentations: Fast and Flexible Image Augmentations”, Buslaev et al., Information, 2020)提供了广泛的此类变换。因此,这种测试也应该被添加到关键的ML组件的测试集中。

模糊测试也可以针对区块链的智能合约进行测试,一般采用基于语法的模糊测试方法,例如可以模拟变量覆盖、影子变量、整数溢出、任意地址写入、代码注入、短地址攻击、不一致性攻击等方面的测试。这类工具有ImmuneBytes、Echidna、ContractFuzzer等。

最好的模糊测试工具与资源

  • https://github.com/TideSec/Peach_Fuzzing
  • https://github.com/aflsmart/aflsmart
  • https://github.com/google/oss-fuzz
  • https://www.microsoft.com/en-us/springfield/
  • http://llvm.org/docs/LibFuzzer.html
  • https://clang.llvm.org/docs/SanitizerCoverage.html
  • https://github.com/crytic/echidna
  • https://github.com/turned2670/DLFuzz
  • https://github.com/Interfish/deep_hunter
  • https://github.com/rohanpadhye/FuzzFactory
  • https://consensys.net/diligence/tools/
  • https://github.com/OpenRCE/sulley