模糊测试基础指南(上)

atp7bkil 技术 2019年4月30日发布
Favorite收藏

导语:本文章从一个较高的层次解释了什么是模糊测试,并简要讨论了模糊测试的原因和反对模糊测试的原因,并且进一步解释了你为什么需要自己动手开始模糊测试以及典型的fuzzer体系架构。

介绍
这篇博文介绍了关于模糊测试的基础知识,以及几种模糊测试工具,并由以下三个部分阐述一些最新的关于fuzzing技术的资讯。

第一部分主要介绍高级模糊测试技术。简要地讨论了使用模糊测试的情景,并进一步解释了开启模糊测试场景以及经典的模糊测试工具的架构。
第二部分主要描述模糊测试入门的过程,并介绍几种通俗易懂,易于理解和使用的模糊测试工具。虽然,通常情况下直接使用现有的fuzzer更为简便,但是由用户自己编写的fuzzer或调整现有的fuzzer可能会产生更好的效果。本文提供的不是一个足够全面完整的列表,而是一系列不同模糊测试技术的示例。
第三部分主要阐述了最近发表的关于模糊测试技术的研究。它将重点关注新型模糊测试技术和经过测试用例已生成技术的公开研究结果。
0 – Fuzzing 101


介绍


本章节将介绍高级模糊测试技术,并简要地讨论了使用模糊测试技术的理由。我将会进一步解释你需要如何开始进行模糊测试以及典型的模糊测试工具的架构。
什么是模糊测试?


Fuzzing或模糊测试是一种自动化的软件测试技术,通常用于识别程序中的潜在漏洞。对程序进行模糊测试是通过向其提供随机输入语句并记录导致程序中的崩溃或非崩溃的内存损坏的测试用例来完成的。在某种意义上,模糊测试就是通过蛮力搜索漏洞。几乎所有需要某种输入的软件都可以进行模糊测试,比如——浏览器,通过查看或编辑文件的应用程序,系统内核,大多数API和其他程序接口,驱动程序,网络守护程序,Web应用程序等等都可以对其进行fuzzing。

fuzzallthethings.jpg


简单的模糊测试不需要任何有关程序的信息,因此,这是一种黑盒测试技术。但是,有一些先进的模糊测试技术可以分析或检测源代码或二进制文件,以便将生成的输入定制到模糊程序,这将是本系列的下一篇博文介绍的内容之一。

为什么选择模糊测试?

Fuzzing 是一种自动发现 bug 的方法; 理想情况下,Fuzzing 可以简单地在机器上运行并且不受干扰。 因为它不需要太多的手动交互,所以它可以是一种廉价的测试技术。另一方面,手工测试非常耗费资源,它揭示的错误数量取决于测试人员的技能。模糊测试和手动测试的结合是最佳的一种做法,因为这两种技术通常会发现不同类型的错误,并且它们可以互补。
应用程序越复杂,就会有越多的 bug,随着复杂性的增加,攻击面也会增加。 对非常复杂的应用程序进行手工测试需要花费大量时间,并且需要良好的测试技能。 例如,如果一个公司决定只手动测试一个浏览器,那么在下一个版本完成之前,就需要很多技能熟练的测试人员来测试整个应用程序。一个fuzzer可以简单的永久运行并且可以在软件发布之前完成测试。 大多数fuzzer的规模相当不错,所以如果需要测试的更快,找到更多的bug,那么你可以只是增加更多的测试机器或更多的CPU内核。也可以使用 Fuzzing 回归测试来确保不会再次引入任何已知的 bug。
作为一个安全研究人员, fuzzing 的确是伟大的,因为一旦一个fuzzer设置好并运行后,你可以解放双手去做其他的事情。
模糊测试的常见问题
虽然 fuzzing 是一个发现bug的伟大且廉价的方法,但它并不总是最佳的选择。这取决于应用程序和期望的缺陷类型,fuzzer 可能需要大量的时间来进行设置才能找到更多的缺陷。特别是那些能够意识到输入结构的可自编写的智能fuzzer的设置将会花费一些工作,直到它产生可用的结果。
一个fuzzer是不能替代其他安全措施的。虽然你有最强大的fuzzer,发现了大量的漏洞,但它不太可能找到一个程序中的每一个漏洞。所以如果你的 fuzzer 没有发现更多的漏洞,这并不意味着你的程序是完全安全的。模糊测试只是对其他安全措施(如定期代码审计和其他安全开发原则)的一个很好的补充。
Fuzzer可以产生许多误报,无法利用的bug以及重复的结果。因此,评审过程是强制性的,无论是手动的还是自动的,这是需要资源的。输入越复杂,评审过程就越复杂。
最大限度地提高Fuzzer的效率是模糊测试最困难的部分之一。一个Fuzzer的价值通常取决于它发现了多少以前未知的bug或漏洞。为了找到更多的 bug,fuzzer 需要有一个高崩溃率的测试用例,这高度依赖于生成的测试用例的质量。通过管道/dev/urandom 到你的目标很容易,但是每个测试用例的崩溃率可能太低,无法在适当的时间窗口中找到任何内容。同时,单个测试用例的执行时间应该尽可能的短。
模糊测试需要什么?
要开始模糊测试,你需要一个接受输入的目标。应用程序越复杂,就越有可能使用fuzzer找到bug。它可以是内部软件,也可以是第三方软件,这取决于你的测试用例。你需要考虑你想要捕捉的bug的类型。一个 fuzzer 需要知道什么时候它发现了一个 bug,所以最容易发现的 bug 是那些导致崩溃的 bug,因为这将表明一个潜在的安全漏洞。
当你清楚你想模糊测试的应用程序和bug类型,那么你有必要思考情况使用什么样的fuzzer。如果你不想从头开始编写模糊测试工具,那么你可以选择许多不同的模糊测试工具。其中一些需要工具一些工作来进行设置,其他的工作则可以迅速完成。因为正确选择模糊测试工具既重要又困难,本系列的下一篇博客文章将介绍一些最重要的 模糊测试工具。
一个fuzzer可以找到什么类型的bug?
理论上,通过模糊测试工具可以找到所有可能的 bug 类型。fuzzer需要一种检测机制来将程序的行为分类为无意的或恶意的。因此,有些 bug 的类比其他 bug 的类在代码中更容易找到,因为它们会产生明显的错误行为。例如,内存损坏bug在触发时导致崩溃是很容易检测到的。另一方面,逻辑错误可能非常难以检测,因为程序没有明显的不正常行为,而且预先定义检测逻辑错误的规则可能比较棘手。
一个典型的fuzzer架构
一个典型的fuzzer由三个不同的部分组成。 一个测试用例生成器生成输入,输入到被测试的程序; 一个worker程序执行给定的输入,并识别意外的行为; 一个日志记录器记录有趣的测试用例以及分析 bug 所需的一切。大多数fuzzer还包括一个服务器或主机,它协调其他三个部分并管理它们之间的通信。

fuzzer-architecture.png

测试用例生成器
测试用例生成器主要负责创建新的测试用例。为了创建新的测试用例,它可以自己识别出输入的结构,这被称为智能fuzzer。相反,不知道输入结构的测试用例生成器被称为愚蠢fuzzer。测试用例可以从头开始生成,也可以从现有的测试用例中变异。复杂的fuzzer也可以将生成和变异结合从而生成测试用例。
模糊测试的导向类型
由测试用例生成器创建的测试用例在质量上有很大的不同。因此,测试用例生成器需要某种指导来决定变更或生成哪些测试用例。最常见的启发式指导是代码覆盖率。理论上,代码覆盖的越多,模糊测试就能发现更多的错误。测试用例生成器可以配置为创建类似于发现新覆盖率测试用例的测试用例。与覆盖率导向的模糊测试类似,基本上所有与发现更多bug相关的指标都可以用作测试用例生成器的指导,例如数据流指导。
愚蠢fuzzer
不需要输入结构模型来生成新测试用例的测试用例生成器称为愚蠢fuzzer。愚蠢fuzzer的优点是它不需要输入结构的信息,因此适合对很多不同的程序进行模糊测试而不需要太多的调整。使用愚蠢fuzzer的最大缺点是,大多数输入需要预定义的结构或包含校验和,fuzzer将很难生成有效的输入,因此主要是测试应用程序的解析代码。
智能fuzzer
与愚蠢fuzzer相反的是一个智能fuzzer,它的测试用例生成器能够理解输入文件的结构。输入文件的结构称为输入模型。例如,输入模型可以是编程语言的语法或数据格式模型。智能fuzzer的优点是它主要创建有效的输入文件,这将导致实际程序中更高的代码覆盖率。然而,一个智能fuzzer通常是高度专业化的特定类型的输入,它需要一个好的输入模型才能够创建测试用例,从而可能触发bug。
基于变异的模糊测试
基于变异的fuzzer是通过变异已知的测试用例来创建新的测试用例。常见的变异技术包括位翻转,即将输入中的随机位进行翻转,或移动、删除、重复输入中的数据块。一个基于变异的fuzzer的主要优点是它需要较少的worker来设置。基于变异的fuzzer的关键部分是选择有趣的测试用例进行变异。这些测试用例需要尽可能不同,使模糊测试达到尽可能多的代码覆盖率,使其更有可能发现bug。例如,如果目标是一个查看和编辑图片的应用程序,并且所选择的测试用例只是 PNG 格式的,那么fuzzer就不太可能覆盖到处理其他文件类型的代码。
基于生成的模糊测试
基于生成的fuzzer会从头开始生成新的测试用例。基于生成的fuzzer需要知道输入文件的结构,否则它们只会生成随机的字节。通常它们需要worker来进行设置,并且专门用于特定的输入类型。 然而,一旦启动并运行之后,它们往往能比基于变异的fuzzer产生更多的代码覆盖率,因此更有可能发现不同的bug。
测试用例最小化
随着时间的推移,由变异创建的测试用例在规模和复杂性上都趋向于增长。这会导致更长的执行时间,并且使得分析有趣的测试用例变得更加困难。较小的测试用例也可以更好地将模糊测试集中在被模糊测试的软件的有趣部分上。因此,fuzzer的测试用例生成引擎也应该能够最小化测试用例。最小化测试用例的目标是找到尽可能小的测试用例,同时触发初始测试用例触发的相同行为。 在这种情况下,相同的行为意味着要么触发相同的崩溃代码,要么满足相同的指导要求。例如,对于覆盖率导向的模糊测试是否意味着在最小化测试用例中命中相同的有趣代码块。这可以通过删除测试用例的某些部分、向目标提供修改后的输入并观察其行为是否仍然满足相同的要求来实现。

本文翻译自:https://labs.mwrinfosecurity.com/blog/what-the-fuzz/如若转载,请注明原文地址: https://www.4hou.com/technology/17684.html
点赞 1
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论