深入探索PHP反序列化函数模糊测试技术

本文详细讨论了PHP反序列化函数的安全问题,提供了使用AFL进行模糊测试的完整脚本和配置方法,帮助开发者发现和修复潜在漏洞,提升代码安全性。

模糊测试PHP的unserialize函数

最近,PHP开发团队决定不再将unserialize函数实现中的bug视为安全问题。在这篇文章中,我想阐述为什么我认为这是一个糟糕的决定,并提供一个简单的设置,用于对unserialize进行模糊测试和持续质量保证,因为似乎正是这个函数漏洞百出的特性促使了这一决定的做出。

分类变更的论据

分类变更的论据有两个方面。首先,他们声称unserialize本质上是一个不安全的函数,用于处理来自不可信来源的数据。本质上,他们是在说,将unserialize实现中的bug视为安全问题没有意义,因为应用程序将不可信数据传递给该函数的事实意味着该应用程序的安全性已经受到损害。其次,他们认为将unserialize bug视为安全问题会鼓励开发者在不可信数据上使用它。在我看来,这是一个相当薄弱的论点。unserialize不安全的警告在文档中非常突出,如果这个警告没有传达出信息,那么我非常怀疑PHP bug跟踪器中的分类变更会起到作用。

让我们稍微详细地讨论第一点,因为实际情况更为微妙。通常,在不攻击unserialize实现本身的情况下,利用不可信数据的unserialize相对容易。但这有一些要求。特别是,攻击者必须能够在目标应用程序或其使用的库中找到包含PHP魔术方法的类,例如__destruct函数。此外,如果提供了unserialize的allowed_classes参数,则包含魔术方法的类必须包含在此列表中。这些条件并不总是成立。如果应用程序是闭源的,攻击者将无法直接找出此类类的名称,如果allowed_classes是空列表,那么他们将无法使用这些类。

上述情况不仅仅是假设场景。这篇相当不错的文章记录了PornHub中一个漏洞的利用,该漏洞要求攻击者针对unserialize实现。正如文章中提到的,应用程序是闭源的事实阻止了他们发现可用于对象注入的类。

我认为大多数人会同意PHP开发团队的观点,即如果应用程序包含对unserialize的调用并传递不可信数据,那么这是一个坏主意,应该修复。然而,将unserialize bug视为普通bug也会不必要地使PHP应用程序开发者及其应用程序用户面临进一步的风险。

有趣的部分

PHP开发团队被unserialize bug淹没的一个原因似乎是,他们在进行更改后要么根本不模糊测试该函数,要么他们的模糊测试机制无效。我完全认识到unserialize实现的功能是复杂的,添加或修改现有代码总是伴随着引入bug的风险。然而,我也相信,通过少量努力,应该可以显著减少发布版本中容易发现的低级bug数量。

无论如何,为了兑现我的承诺,我上传了一个脚本和辅助文件的存储库,用于构建PHP并通过AFL对unserialize进行模糊测试。没有秘密配方。如果有的话,那就是重点;对现有unserialize实现及其更改的持续健全性检查可以轻松自动化。

脚本很简单,但有一些值得注意的地方:

  • 驱动程序PHP脚本从文件加载表示要反序列化的数据的字符串,并将其直接传递给unserialize。这应该足以找到我之前知道的在unserialize中修复的相当一部分bug,例如像这样的东西。然而,如果需要一些额外的PHP代码来触发bug,那么它将不会被找到,例如像这样的东西。通过借鉴其他博客文章中的想法,扩展模糊测试设置应该相对容易,例如,上面提到的PornHub漏洞利用的作者在这篇文章中提出了一些好主意。
  • 可以使用AFL的检测工具构建整个PHP,或者只构建认为与unserialize功能相关的组件。前者的优点是保证AFL可以智能地探索所有可能通过unserialize触发的功能,缺点是速度较慢。build.sh脚本目前使用AFL的检测工具编译所有内容。如果您想要更快的二进制文件,可以编译没有AFL/ASAN的PHP,删除与unserialize相关的目标文件,重新配置构建以使用AFL/ASAN,然后重新编译这些目标文件。我过去使用过这种方法,效果很好,但您需要确保重新编译所有与unserialize可能触发的代码相关的目标文件,否则AFL将无法在那里跟踪覆盖率。
  • 可以向AFL提供一个令牌字典,用于模糊测试。存储库中的字典包含从unserialize解析器中提取的令牌,我认为它相当完整,但如果我遗漏了什么,请告诉我,我一定会包含它。
  • 提供给AFL进行模糊测试的种子文件对其发现bug的能力以及发现特定bug的速度有显著影响。我提供的种子文件是从PHP文档中找到的有效unserialize用法示例和先前漏洞的触发器中构建的。如果您发现有有用的种子文件,请随时告诉我。
  • 我通过从我的模糊测试机器中提取文件和配置创建了这个存储库,目标是忠实再现我过去用于发现大量unserialize bug的设置。然而,我可能忘记了一些东西,或者在整理发布过程中破坏了一些东西。在我写这篇文章时,我已经启动了fuzz.sh脚本来确保一切正常,但可能我搞砸了什么而没有注意到。如果确实如此,请告诉我!如果您想确认一切功能正常,请编译PHP版本5.6.11,您应该在大约4000万次执行内找到这个bug。

祝狩猎愉快!

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计