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

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

模糊测试PHP的unserialize函数

最近,PHP开发团队决定不再将unserialize函数实现中的bug视为安全问题。在本文中,我想概述为什么我认为这是一个坏主意,并提供一套简单的设置,用于对unserialize进行模糊测试和持续质量保证,因为似乎正是它无穷无尽的bug是这一举措的部分动机。

分类变更的论点有两个。首先,他们声称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的风险。然而,我也相信,通过少量努力,应该可以显著减少发布版本中低挂果实的数量。

无论如何,为了兑现我的承诺,我上传了一个脚本和辅助文件的存储库,用于通过AFL构建PHP和模糊测试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 设计