模糊测试增强了物联网设备的安全性

文章作者:DeWitt C. Seward

模糊测试可用于有效地加固嵌入式网络栈,从而加强物联网设备的安全性。

随着物联网设备的普及,嵌入式安全攻击也在增加。历史上,嵌入式系统工程师忽略了设备层的安全性,尽管嵌入式设备的许多领域容易出现漏洞。串行端口、无线电接口,甚至编程/调试接口都可能被黑客利用。模糊测试是工程师寻找嵌入式设备弱点的重要场所,应该被考虑用于强化物联网设备接口。

什么是模糊测试?

模糊测试就像虚构的百万猴子随机输入来写莎士比亚。在实践中,小说作品需要许多随机组合来产生一个简单的短语,但对于嵌入式系统,我们只需要从一个已知的好句子中改变几个字母。

有许多商业和开源工具可用于实现模糊攻击。这些工具生成随机字节串,也称为模糊向量或攻击向量,并将它们提交到正在测试的界面,跟踪可能显示bug的结果行为。

模糊测试是一种数字游戏,但我们不能尝试无限数量的可能输入。相反,我们专注于通过最大化模糊向量提交率、模糊向量的有效性和bug检测算法来优化测试时间。

模糊测试的概念

因为许多fuzz测试工具都是为测试PC应用程序而设计的,所以如果将嵌入式代码作为本机编译的PC应用程序运行,就更容易对其进行调整。在PC上运行嵌入式代码会产生巨大的性能优势,但也有两个缺点。首先,PC微处理器的反应与嵌入式微控制器不同。其次,我们必须重写任何与硬件有关的代码。然而,在实际操作中,在PC上运行的优点超过了缺点。真正的障碍是将代码移植到PC上进行本地编译的困难。

我们怎么知道模糊向量何时触发了一个bug?崩溃很容易被发现,但是很难识别导致重置的模糊向量。内存溢出错误或指针走散写(对黑客最有价值的错误类型)几乎不可能从系统外部辨别出来,因为它们通常不会导致崩溃或重置。

许多现代编译器,如GCC和Clang,都有一个称为内存无害化的特性。这将内存块标记为干净或脏,这取决于它们是否在使用中,并标记任何访问脏内存的尝试。但是,内存清理需要消耗flash、RAM和CPU周期,这使得它难以在嵌入式设备上运行。所以,我们可以测试代码的子集,用更多资源构建设备版本,或者使用PC。

测试的有效性可以通过执行代码的数量来评估。在这里,编译器也可以通过使用面包屑子例程调用来跟踪内存使用情况。代码覆盖库为每个代码路径维护一个使用值表,并在执行面包屑时将它们递增。

然而,代码覆盖率数字对于嵌入式模糊测试来说是难以解释的,因为大部分代码是模糊向量无法访问的;例如,独立于接口运行的外设设备驱动程序。因此,很难为嵌入式系统定义“完整的代码覆盖范围”——可能只有20%的嵌入式代码是可访问的。代码覆盖还会消耗大量的flash、RAM和CPU周期,并且需要专门的硬件或PC目标才能运行。

Bug报告

当模糊测试发现一个导致不希望的行为的向量时,我们需要详细的信息。bug发生在哪里?调用堆栈的状态是什么?bug的具体类型是什么?所有这些信息有助于分类并最终修复bug。

缺陷分类在模糊测试中是至关重要的。新的模糊项目经常会发现许多bug,我们需要一种自动的方法来确定它们的严重性。此外,模糊错误往往会阻止错误,因为它们经常会掩盖代码路径中进一步出现的其他错误。我们需要快速解决在模糊测试中出现的问题。

嵌入式客户端不像pc那样愿意公开自己的信息。通常,崩溃只会导致设备重新启动。虽然这在该领域是理想的,但它会擦除设备的状态,使得很难了解是否发生了崩溃、崩溃发生的地点或原因,或者所采取的代码路径。工程师必须找到一个一致的复制向量,然后使用调试器跟踪不良行为并找到错误。

在模糊测试中,一个测试可能会为一些bug产生数千个崩溃向量,给人一种有bug系统的错误印象。重要的是要快速确定哪些向量与相同的底层bug相关。对于嵌入式设备,崩溃本身的位置对于bug来说通常是唯一的,并且通常不需要找到完整的调用堆栈跟踪。

连续模糊测试

由于模糊测试的随机性,长时间运行它们会增加发现问题的机会。但是,任何项目计划都不能消除开发结束时冗长的模糊测试周期带来的延迟。

在实践中,模糊测试将在发布过程之后在它自己的分支上开始。任何新发现的bug都将在本地分支中修复,这样测试就可以继续进行,而不会因为新bug而阻碍其他bug的发现。作为发布周期的一部分,将评估从先前版本的模糊测试中发现的bug,以便将其包含在新版本中。最后,应该将发现bug的模糊向量添加到正常的质量保证过程中,以验证修复,并确保这些bug不会无意中重新引入代码中。

我们应该在不同的场景下对设备进行模糊测试;例如,一个设备在联网时对连接请求的响应是不同的。在每个可能的场景上运行模糊测试是不现实的,但是我们可以为每个可能的状态值包括模糊测试。例如,使用每种不同的设备类型运行fuzz测试,同时保持其他变量相同。然后为另一个变量运行不同的值,例如为一种设备类型运行网络连接状态。

模糊测试架构

两个突出的模糊测试体系结构是定向模糊,其中模糊向量由工程师在测试前指定,以及覆盖引导的模糊测试,其中模糊工具从一组初始测试向量开始,并根据包对代码的渗透程度自动改变它们。

此外,并非所有代码都能在PC上运行,为嵌入式应用程序开发PC模拟器可能不切实际,这取决于所测试的内容。

下面是四个模糊测试架构的总结:

  • 嵌入式硬件上的直接接口测试-通过接口注入模糊包在嵌入式设备上运行正常的生产映像
  • 包(栈)注入测试——直接调用传入包例程,而不必通过空中运行接口
  • 利用基于pc的仿真技术开发和测试嵌入式代码的模拟器进行定向模糊
  • 覆盖导向的模糊与模拟器(如下所示Libfuzz)

比较模糊测试体系结构的表

多个模糊测试人员

在用调试接口锁定和安全引导锁定嵌入式设备之后,我们需要考虑对设备的接口进行模糊测试。许多用于保护web服务器的相同工具和概念可以用于嵌入式设备。

使用合适的工具。覆盖引导的fuzzers对于连续的模糊测试是必要的,但是如果您的代码只在嵌入式硬件上执行,定向的fuzzers对于提供某种程度的模糊测试覆盖是一个很好的选择。

最后,您应该在尽可能多的场景中使用多个fuzz测试人员,因为每个测试人员对设备的测试略有不同,从而最大化覆盖范围,从而提高嵌入式设备的安全性。

本文最初发表于经济日报

这是硅谷实验室的德威特·苏厄德的大头照 德威特·苏厄德(DeWitt C. Seward)是硅谷实验室的首席工程师。

相关文章:

留下你的评论