资讯详情

面试官:了解Fuzzing Test吗?

专注于测试圈、自动化测试、测试平台开发、测试新技术、大, 可以帮忙内推BATJ等大厂!欢迎加入VX沟通交流: ISTE1024

什么是 "模糊测试"?

Fuzzing 这是一种发现软件缺陷的方法,它通过随机输入程序来找到导致程序崩溃的测试场景(原理有点相似Monkey Test)。它可以帮助你快速理解程序的整体强度,并帮助你发现和修复关键缺陷。

它是一种不需要访问源代码的黑盒测试技术,但它仍然可以用来测试那些有源代码的软件。这是因为它可以更快地发现缺陷,并降低大量的代码评估成本。

模糊测试的优缺点

Fuzzing虽然在某些业务中很有用,但毕竟不是银弹。以下是模糊技术的一些优缺点。

优点

  • 可以说不费“吹灰之力”就能得到结果--一旦fuzzer它可以在没有交互的情况下停留几个小时、几天或几个月来发现错误。

  • 人工审计中遗漏的错误可以发现

  • 它可以为目标软件的强度提供一个完整的概述

缺点

  • 一切都不会耗尽bug--模糊测试可能会错过那些不会触发整个程序崩溃的人bug,而且对于那些只在非常特殊情况下触发的人bug也很难覆盖。

  • 崩溃测试用例可能很难分析,因为模糊测试行为不能告诉你软件内部运行模式的知识。

  • 输入复杂的程序可能需要更多的工作来生成足够聪明的模糊测试器,以获得足够的代码覆盖率。

Smart/Dumb模糊测试

Fuzzers为软件系统提供随机输入。内容形式可能是用户可以直接输入的某种网络协议、某种格式的文件或数据。它的输入模式是完全随机的,不知道预期的输入应该是什么样子,或者在一些修改后看起来有效。

产生完全随机输入Fuzzer被称为 Dumb Fuzzer。少量的工作可以以很少的成本产生结果——这是模糊测试的主要优势。然而,有时一个程序只在输入的特定场景中进行处理。例如,需要输入程序 "name"与字段相关的字段 "name length"。

如果程序识别的字段没有以足够有效的形式出现,它可能永远不会读取这个名字。如果这些字段以有效的形式存在,但长度值被设置为不正确的值,程序可能会读取包含名称的缓冲区,并导致崩溃。如果有效的输入是不可能的。在这种情况下,可以使用 Smart Fuzzer,Smart Fuzzer以输入特定规则为基础,如协议定义或文件格式规则。它可以构建大部分有效的输入,只模糊基本格式中的输入。

Fuzzers的类型

广义上讲,Fuzzer基于变异和基于生成的程序输入可分为两类.

基于突变的Fuzzer可以说是最容易创建的类型之一。该技术适用于Dumb Fuzzer,但也可用于智能Fuzzer。有效输入的样本通过突变随机突变产生畸形输入。

dumb mutation Fuzzer您可以简单地选择一个有效的输入样本,并随机更改其部分。由于输入通常与有效输入有足够的相似性,这意味着良好的代码覆盖可以在不进一步智能处理的情况下实现。

以下是基于突变的Fuzzer两种可用技术。

Fuzzer样本输入可以保存,突变后可以重播。这对文件格式的模糊处理非常有效,可以为目标程序保存一些样本文件并进行模糊处理。

简单或无状态的网络协议也可以通过重放来有效地模糊,因为Fuzzer没有必要在协议中提出大量的法律请求。对于更复杂的协议协议可能更困难。这是因为Fuzzer需要动态响应程序,允许继续深入处理协议。

你可能听说过中间人()它是一种基于突变的网络协议模糊测试的渗透测试者和黑客的技术。MITM,您位于客户端和服务器之间,截获并可能修改它们之间传递的信息。这样,你就像两者之间的代理。

通过将你的Fuzzer作为代理,它可以根据您对服务器或客户端的模糊处理来改变请求或响应。同样,Fuzzer您可以随机更改一些请求,也可以在您感兴趣的协议的特定层次上智能定请求。基于代理的模糊测试可以让你利用现有的网络程序部署架构,快速插入模糊测试层,而不需要让你的fuzzer像客户端或服务器本身一样行动。

基于生成的Fuzzer事实上,输入是从零开始生成的,而不是现有输入的突然变化。它们通常需要一定程度的智能来构建至少对程序有意义的输入,尽管在技术上生成完全随机的数据。

生成Fuzzer协议或文件格式通常分为几块,可以按有效顺序建立,并随机模糊其中一些块。这可以创建输入来保留其整体结构,但也包含不一致的数据。这些块的粒度和构建这些块的智能度决定了这些块的粒度Fuzzer智能水平。虽然基于突变的模糊处理可以产生与生成模糊处理类似的效果(因为随着时间的推移,突变将被随机应用,而不会完全破坏输入的结构),但生成输入可以确保这种情况的发生。

生成fuzzers它也可以更容易地深入到协议中,因为它可以构建有效的输入序列,模糊通信的特定部分。它还允许Fuzzer作为真正的客户/服务器,产生正确、动态的响应,但这些响应不能盲目重放。

进化模糊试验是一种先进的技术。它允许Fuzzer使用每个测试用例的反馈来了解随时间推移输入的格式。例如,通过测量每个测试用例的代码覆盖率,Fuzzer可以计算出测试用例的哪些属性可以锻炼给定的代码区域,并逐变出一套覆盖大多数程序代码的测试用例。进化模糊测试通常依赖于其他类似于遗传算法的技术,可能需要某种形式的二进制工具来正确操作。

什么是模糊测试?

即使是相对dumb模糊测试,还要记住你的测试用例实际上有可能击中代码的哪一部分。举个简单的例子,如果你正在探索使用它TCP/IP而你的Fuzzers原始数据包的捕获随机突变,你很可能会被破坏TCP/IP数据包本身。因此,应用程序无法处理您的输入。再者,如果你正在测试一个将文本的图像解析为真实文本的OCR但是你正在突变整个图像文件,你最终可能会更频繁地测试它的图像解析代码,而不是实际的OCR代码。假如你想专门针对这个OCR您可能希望保持图像文件的标题有效。

为有效运行,Fuzzer执行以下重要任务:

  • 生成测试用例

  • 记录测试用例或再现用例所需的任何信息

  • 为目标程序接口提供测试case作为输入

  • 检测崩溃

Fuzzer许多任务通常被分成独立的模块。例如,一个库可以突变数据或根据定义生成数据,另一个库可以向目标程序提供测试用例等。

测试用例的生成将取决于基于突变或基于生成的模糊处理。无论采用哪种方法,都会有一些东西需要随机转换,无论是特定类型的字段还是任何数据块。

这些转换可以是完全随机的,但值得注意的是,边界和极端情况往往是程序中错误的来源。所以,你可能想偏爱这种情况。

  • 非常长的超长字符串或Null

  • 能够支持的最大值和最小值整数

  • 像-1、0、1和2这样的值

根据你想要模糊的内容,可能会有一些特定的值或字符更容易触发bug。比如:

  • Null

  • 分号

  • 格式化字符串值(%)n,%s等等)

  • 应用特定的关键词

重现测试用例的最简单方法是记录在崩溃时使用的确切输入。在某些情况下,还有其他方法可以实现再现。一种方法是存储用于测试用例生成的随机部分的初始种子,并确保所有后续随机行为都遵循可追溯到种子的路径。用相同的种子重新运行Fuzzer,行为应该是可重复的。例如,您只能记录测试用例编号和初始种子,然后快速重新生成,直到达到给定的测试用例。

当目标程序可能基于过去的输入积累依赖性时,该技术非常有用。以前的输入可能会导致程序在内存中初始化各种项目,这是触发错误所必需的。在这些情况下下,简单地记录崩溃的测试用例并不足以重现该错误。

与目标程序连接以提供模糊输入通常是简单的。对于网络协议,它可能涉及在网络上发送测试用例,或响应客户的请求。对于文件格式,它可能意味着用一个指向测试用例的命令行参数来执行程序。然而,有时提供的输入的形式不容易以自动化的方式生成,或者编写程序脚本来执行每个测试用例的开销很大,证明是非常缓慢的。在这些情况下,创造性的思考可以发现用正确的数据来锻炼相关的代码片断的方法。

例如,这可以通过在内存中人为地设置程序来执行解析功能,而输入的参数完全在内存中。这可以消除程序在每个测试用例之前经过冗长的加载程序的需要。而且,通过让测试用例完全在内存中生成和提供,而不是通过硬盘驱动器,可以进一步提高速度。

崩溃检测是模糊测试的关键。如果你不能准确地确定一个程序何时崩溃,你就不能确定一个测试用例是否触发了一个错误。

  • 附加一个调试器

这可以为你提供最准确的结果,你可以编写调试器的脚本,以便在检测到崩溃时立即为你提供崩溃跟踪。然而,附加一个调试器会大大降低程序的速度,并会造成相当大的开销。在给定的时间内,你能产生的测试用例越少,你发现崩溃的机会就越少。

  • 看看目标进程是否消失了

与其附加一个调试器,你可以简单地看看在执行测试用例后,目标的进程ID是否仍然存在于系统中。如果进程消失了,它可能已经崩溃了。如果你想了解更多关于崩溃的信息,你可以在以后用调试器重新运行测试用例。你甚至可以在每次崩溃时自动这样做,同时还可以避免在每个案例中都连接调试器而导致的速度下降。

如果程序对你的测试用例有正常的响应,你可以设置一个超时,超时后你就认为程序已经崩溃。这也可以检测出导致程序无反应但不一定终止的错误。

无论你使用哪种方法,只要程序崩溃或变得无反应,就应该重新启动,以便让模糊测试继续进行。

模糊测试的质量

你可以做一些事情来衡量或提高你的模糊测试的质量。虽然这些都是需要记住的有用的东西,但如果你已经在一定的时间范围内得到了很多独特的崩溃,你可能不需要再为这些事情费心了。

速度可能是模糊测试中最重要的因素之一。你每秒钟/每分钟能运行多少个测试用例?合理的数值当然取决于目标,但你能执行的测试用例越多,你就越有可能在给定的时间段内发现崩溃。模糊测试是随机的,所以每一个测试用例就像一张彩票,你要尽可能多地得到它们。

你可以做很多事情来提高测试用例的速度,比如提高生成或变异例程的效率,并行化测试用例,减少超时,或在不显示图形用户界面的 "无头 "模式下运行程序。如果你想的话,你可以简单地购买更快的套件

找到崩溃只是过程的开始。一旦你找到一个崩溃的测试用例,你就需要分析它,找出错误所在,并根据你的动机,修复它或为它编写一个漏洞。如果你有成千上万个崩溃的测试用例,这可能是相当令人生畏的。通过对崩溃进行分类,你可以根据哪些崩溃是你最感兴趣的来确定它们的优先次序。这也可以帮助你识别一个测试用例何时触发了与另一个相同的错误,所以你只保留与独特崩溃有关的案例。

为了做到这一点,你需要一些关于崩溃的自动信息,以便你能做出决定。在目标机上运行测试用例并连接到调试器,可以提供崩溃跟踪,你可以对其进行分析,找到诸如异常类型、寄存器值、堆栈内容等值。

由于模糊测试是随机改变输入的,一个崩溃的测试用例通常会有多个与触发该错误无关的改变。测试用例缩减是将测试用例缩减到触发bug所需的有效输入的最小改动集,因此你只需要在分析中关注输入的这一部分。

这种减少可以手动进行,但也可以由Fuzzer自动进行。当遇到一个崩溃的测试用例时,Fuzzer可以重新执行该测试用例几次。每一次,它都会逐渐减少对输入的改动,直到剩下最小的一组改动,同时仍然触发该错误。这可以简化你的分析,并有助于对崩溃的测试用例进行分类,因为你会准确知道输入的哪些部分受到影响。

这是一个衡量程序的代码有多少被Fuzzer执行的标准。其原理是,你得到的覆盖率越多,你实际测试的程序就越多。测量代码覆盖率可能很棘手,通常需要二进制仪器来跟踪代码的哪些部分正在被执行。你也可以用不同的方式测量代码覆盖率,比如按行、按基本块、按分支或按代码路径。

代码覆盖率对于模糊测试来说并不是一个完美的衡量标准,因为有可能在执行代码的同时并没有发现其中的漏洞。而且,经常有一些代码区域几乎不会被执行,例如安全错误检查,反正我们不太可能真正需要,也不太感兴趣。尽管如此,某种形式的代码覆盖率测量可以让我们了解到你的Fuzzer在程序中触发了什么。特别是当你的模糊测试是完全黑箱的时候,你可能还不太了解程序的内部运作。一些可能有助于代码覆盖率的工具和技术包括Pai Mei、Valgrind、DynamoRIO和DTrace。

模糊测试框架

目前市面上有许多框架可以让你创建Fuzzer,而不必从头开始造。下面列出了这些框架:

Radamsa

Radamsa被设计为易于使用和灵活。它试图对各种输入类型进行 "公正的工作",并包含一些不同的模糊算法进行突变。

Sulley

Sulley提供了一个全面的生成框架,允许结构化数据被表示为基于生成的模糊处理。它还包含帮助记录测试用例和检测崩溃的组件。

Peach

Peach框架可以对文件格式和网络协议进行智能模糊测试。它可以执行基于生成和突变的模糊测试,并包含帮助建立模型和监控目标的组件。

SPIKE

SPIKE是一个网络协议Fuzzer。它需要用户熟悉掌握C语言,并被设计为在Linux上运行。

Grinder

Grinder是一个网络浏览器Fuzzer,它还具有帮助管理大量崩溃的功能。

NodeFuzz

NodeFuzz是一个基于node.js的网络浏览器线束,它包括仪器模块,可以从客户端获得更多信息。

AFL

AFL是一个灰盒式的模糊测试工具,利用编译在目标代码中的仪器。AFL最初是为Linux中的C和C++程序编写的,后来被分叉以支持Windows、Java和.Net。

往期推荐

接口测试框架开发实践4:HTTP方法封装

接口测试框架开发实践3:用例管理模块

经验分享|测试工程师转型测试开发历程

接口测试框架开发实践5:配置文件读取

接口测试框架开发实践2:接口自动化测试框架设计思路

接口自动化测试框架实践1:接口测试概述

Pytest系列(7)-数据驱动测试DDT

标签: 连接器对接线束

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台