介绍DIFFER:用于测试和验证转换后程序的新工具
我们最近发布了一款名为DIFFER的新型差分测试工具,用于发现转换后程序中的错误和健全性违规。DIFFER融合了差分测试、回归测试和模糊测试的元素,帮助用户发现经过软件重写、精简和加固工具修改后的程序缺陷。使用DIFFER对10款软件精简工具进行评估时,它成功发现了这些工具产生的转换程序中71%存在精简失败或健全性违规问题。
背景
软件转换在过去十年中一直是热门研究领域,主要动力来自保护遗留软件的安全需求。在许多情况下,这项工作必须在没有软件源代码(仅二进制文件)的情况下完成,因为源代码可能丢失、受供应商锁定或由于过时的构建链无法重新编译。该领域涌现的热门研究方向包括二进制提升、重新编译、重写、修补、加固和精简。
虽然为实现这些目标构建的工具取得了一定成功,但它们也带来显著风险。当编译器将源代码降级为二进制文件时,一旦不再需要上下文信息就会将其丢弃。程序被降级为二进制后,安全修改原始程序所需的上下文信息通常无法完全恢复。因此,直接修改程序二进制的工具可能会无意中破坏程序,引入新的错误和漏洞。
尽管DIFFER是应用无关的,但我们最初构建这个工具是为了帮助发现使用精简工具(如Carve、Trimmer、Razor)移除不必要功能后程序中的错误。软件精简工具通常通过移除可能包含潜在漏洞或被攻击者通过代码重用攻击模式利用的不必要代码,来最小化程序的攻击面。精简工具通常会对程序执行分析过程,将功能映射到执行所需的代码。然后使用这些映射来切除用户不需要的功能对应的代码。然而,这些切除可能不精确,因为生成映射依赖于二进制恢复等不精确的分析步骤。因此,精简程序在切除过程中可能引入新的错误和漏洞,而这正是DIFFER设计用来检测的问题。
DIFFER如何工作?
在高层次上,DIFFER(如图1所示)用于测试程序的未修改版本与一个或多个修改变体。DIFFER允许用户指定对应于未修改和修改程序行为及功能的种子输入。然后使用这些输入运行原始程序和转换变体,并比较输出结果。此外,DIFFER支持基于模板的种子输入变异模糊测试。通过提供变异模板,DIFFER可以最大化输入空间的覆盖范围,避免遗漏错误(即假阴性)。
当提供对应于未修改功能的输入时,DIFFER期望看到原始程序和变体程序产生相同的输出。相反,当使用对应于修改功能的输入执行程序时,它期望看到不同的输出。如果DIFFER检测到意外的匹配、差异或崩溃输出,会向用户报告。这些报告帮助用户识别转换过程或其配置导致的修改程序错误。
图1:DIFFER概述
在配置DIFFER时,用户选择一个或多个比较器来比较输出。虽然DIFFER提供了许多内置比较器来检查基本输出(如返回码、控制台文本和输出文件),但通常需要更高级的比较器。为此,DIFFER允许用户为复杂输出(如数据包捕获)添加自定义比较器。自定义比较器还可通过定义允许的输出差异(如控制台输出中的时间戳)来减少误报。我们的DIFFER开源版本包含许多有用的比较器实现,帮助用户轻松编写自己的比较器。
然而,DIFFER不能也不提供转换工具或其产生的修改程序健全性的形式化保证。与其他动态分析测试方法一样,DIFFER在一般情况下无法穷尽测试复杂程序的输入空间。
应用案例:评估软件精简工具
在我们最近与GrammaTech合作进行的一项研究中,使用DIFFER评估了10种不同软件精简工具创建的精简程序。我们使用这些工具从20个不同规模、复杂度和用途的程序中移除不必要功能。这些工具共同创建了90个精简变体程序,然后使用DIFFER进行验证。DIFFER发现其中39个变体(约43%)仍存在精简工具未能移除的功能。更糟糕的是,DIFFER发现25个变体(约28%)在精简后要么崩溃,要么在保留功能中产生不正确输出。
通过发现这些故障,DIFFER证明了自己作为转换后验证工具的价值。尽管这项研究专注于精简转换,但我们想强调DIFFER足够通用,可以测试其他转换工具,如用于软件加固(如CFI、堆栈保护)、翻译(如C到Rust转换器)和代理(如ML代理生成器)的工具。
未来计划
随着DIFFER作为开源软件发布,我们邀请安全研究社区通过拉取请求使用、扩展和帮助维护DIFFER。我们计划进行几项具体改进,包括:
- 支持在Docker容器中运行二进制文件以减少环境负担
- 添加新的内置比较器
- 增加对需要超级用户权限目标的支持
- 支持监控构成分布式系统的多个进程
- 通过插桩等方式添加运行时比较器,进行"深度"等价性检查
致谢
本材料基于海军研究办公室(ONR)根据合同号N00014-21-C-1032支持的工作。本材料中表达的任何观点、发现和结论或建议均为作者观点,不一定反映ONR的观点。
分享至:Twitter、LinkedIn、GitHub、Mastodon、Hacker News