– 如需转载请注明出处,侵权必究 –
FUGIO: Automatic Exploit Generation for PHP Object Injection Vulnerabilities
本文发表于USENIX Security 2022,第一作者是来自韩国科学技术院的Sunnyeo Park。论文结合了动静态分析以及模糊测试技术,提出了一种可以用于挖掘并利用POI(PHP object injection)漏洞的工具fugio。
PHP对象注入(POI)漏洞是一种安全关键缺陷,它允许在易受攻击的PHP应用程序中远程执行类方法的代码。利用这个漏洞通常需要复杂的面向属性编程来塑造注入对象。现有的现成工具只关注于识别潜在的POI漏洞,而没有确认任何利用对象的存在。为此,文章提出了FUGIO,第一个针对POI漏洞的自动攻击生成(AEG)工具。FUGIO进行粗粒度的静态和动态程序分析,以生成一个gadgets链列表,作为利用对象的蓝图。FUGIO然后利用这些识别出的链进行追踪活动,并产生攻击对象。
1. 背景
PHP对象注入(POI)漏洞是一个安全关键的PHP应用程序bug,它支持各种攻击,包括跨站点脚本编写、SQL注入和任意文件删除。PHP支持将字符串反序列化为PHP对象的功能,以方便对运行时对象的管理。当利用POI漏洞时,攻击者的目标是此功能;对手将伪造的字符串传递给反序列化函数调用,从而将任意PHP对象注入到目标应用程序作用域。
Property-oriented programming:当利用POI漏洞时,攻击者通过仔细选择其属性值来调用现有的类方法或函数链来构建注入对象。这个链反映了一个调用堆栈,它从入口方法开始,以调用具有攻击有效负载的安全敏感函数的方法结束。这个链称为POP链,这个POP链的每个方法都称为一个gadget。
反序列化:PHP支持两个开发人员经常用来编码和解码对象类型数据的内置函数:serialize()和unserialize()。这些方法分别用于将给定对象序列化为字符串和将给定字符串转换为对象。当对PHP Archive (PHAR)文件(如file_exists和is_file)执行文件操作时,也会发生反序列化,因为该文件类型以序列化的形式存储元数据。因此,对手可以在运行时通过向非序列化调用提供输入字符串或对攻击者上传的文件触发文件操作来注入任意对象。
2. 方法设计
1. POI检测器(POI检测器通过动态测试检测目标PHP应用程序中的潜在POI漏洞。具体来说,它会动态检测接收预定义输入字符串的注入点,并将其转换为PHP对象。)
2. 静态分析器(静态分析器为用户定义的类和函数计算静态摘要,这些类和函数后来用于生成POP链和POP链标识符的PUT)
3. 动态分析器(动态分析器计算动态生成的类和函数的函数摘要和类摘要,这些类和函数在目标应用程序源代码中没有静态定义。这些摘要随后也会被POP链标识符用于生成链和PUT)
4. POP链标识符(根据来自静态和动态分析器的信息,POP链标识符会发出一个可用POP链列表,并在执行模糊测试时使用。)
5. POP链Fuzzer(给定一个PUT和一个POP链,模糊器对PUT进行反馈驱动的模糊处理,生成利用对象。)
3. 评估
从以下几个方面进行了评估:
1. 生成攻击对象的效率
上表总结了评价结果。第三列表示识别出的POP链的数量,第四列表示进行模糊处理以产生exploit的POP链的数量。Covered sink列表示检测到的POP链中唯一敏感sink的数量。
在30个app中,FUGIO共报告了68个E链。文章作者手工验证了这些E链,并证实FUGIO没有产生假阳性。在66家PE链中,有26个是真正可以利用的。FUGIO从27个漏洞应用程序中分别生成了利用对象
2. 与之前的开源工具效率进行对比
Dahse等人的静态方法报告了10个假阳性,因为静态解析的call-site阻碍了污染数据流分析。这意味着分析器应该检查所有报告的可利用性,包括这些误报。相比之下,FUGIO没有报告误报,因为它使用生成的对象执行PUT,并使用exploit oracle确认可利用性。
上表显示了FUGIO在21个PHPGGC应用中生成攻击对象能力的实验结果。表中的第二列表示PHPGGC列出的已知可利用链的数量。第三列显示FUGIO识别出的gadget链的数量,第四列表示对这些识别出的链产生的利用的数量。最后一列显示FUGIO发现的新可利用链的数量,以及它们的利用对象。对于PHPGGC中的39个可利用链,FUGIO报告了34个链和22个利用对象。此外,FUGIO发现了32个新的可利用链及其利用对象,总共产生了54个可利用链及其利用对象。
3. 文章演示了几个参数影响实际效率的程度
对于30个应用中的每个敏感接收器,文章最多采样了10个链,其中最后一个gadget有这个sink;抽样的POP链总数为13,582个。对于每个采样链,文章运行了5次模糊器,超时时间为300秒。该模糊器共生成408条E链和662条(PE+E)链。对于每个PE或E链,文章作者测量了模糊器生成攻击对象所花费的时间。然后,计算在特定的时间内生成利用对象的链的数量,从0秒到300秒,增量为10秒。最终将结果绘制在5a中。
作者将最大链长设置为从1到10的值,并为每个条件采样POP链。例如,如果最大链长设置为3,则在长度为1、2、3的链中进行采样。FUGIO对采样的链条进行了五次fuzzing活动,使用了100秒的超时时间。最后计算了E条链的总数,以及每个最大链长产生的PE和E条链。实验结果如图b所示。
4. 评估了FUGIO在发现之前未报告的POI漏洞及其漏洞利用方面的能力
两个PHP应用程序的最新版本中评估了FUGIO的效果:带有WooCommerce的WordPress 5.4.2和Concrete5 8.5.4。WooCommerce是最流行的WordPress插件之一,超过500万活跃安装。在Concrete5中,FUGIO在201个敏感sink的5016条链中发现了4条具有开发对象的可开发链。三条链及其可利用对象使攻击者能够删除任意文件,而剩下的一条链及其可利用对象使攻击者能够使用其选择的参数调用任何用户定义函数。
5. 总结
该文章作者提出FUGIO,第一个针对POI漏洞的AEG工具。提出了一系列的静态分析、动态分析和模糊技术来计算POP链和生成利用。FUGIO报告了来自30个实际PHP应用程序的68个已知POI漏洞的利用对象。FUGIO还报告了两个以前未知的POI漏洞和功能利用对象,证明了FUGIO在显著减轻繁重的面向属性编程负担方面的有效性
6. Q&A
-
针对POI漏洞的AEG需要解决两个挑战:
-
在考虑这些gadget的可用性及其调用者–被调用者关系时,有必要识别由称为gadget的用户定义方法和函数组成的可用POP链
-
对于每个确定的链,它应该通过正确设置对象层次结构和它的多个属性来塑造一个注入对象,从而遵循这个POP链指定的执行流。
-
FUGIO如何解决上文中提到的两个挑战
-
通过分析动态生成的类以及静态定义的类来识别所有POP链,并在触发目标POI漏洞时删除不可用的gadget
-
FUGIO生成利用对象,这些利用对象通过在一个被调试的PHP应用程序上执行反馈驱动的fuzzing来跟踪已识别链的执行。
-
为了调用前一个gadget body中的下一个gadget,攻击者需要针对注入体的一些属性进行调整,下一个gadget应该满足:
-
包含上一个gadget类的成员方法
-
不同类的成员方法,其名称在上一个gadget调用语句中被使用
-
没有owner class的用户定义方法
-
对POI漏洞执行AEG必须实现哪三个目标?
-
找到POI漏洞
-
在触发已识别的漏洞时,识别可用gadget的POP链
-
为识别出的可利用的POP链生成输入对象,从而报告漏洞的可行性
4.1 针对第一二个目标提出哪几个挑战以及解决方法
-
PHP的动态特性导致很难找出可加载类和gadgets
-
在评估可行性时,连接可加载gadgets的算法会产生数量惊人的POP链,审查难度大
解决方法:
1. 结合动静态分析
2. 执行粗粒度的污点分析来对POP链剪枝,并执行深度有界的广度优先搜索,枚举所有有希望的链
4.2 针对fuzzing提出哪两个技术挑战以及解决方法
-
在大型PHP应用程序上执行无状态fuzzing时,很难建立高吞吐量。
-
通过fuzzing化设计一个具有多个属性值的攻击对象并非易事。
解决方法:
-
FUGIO合成了一个用于测试的程序(PUT),该程序模拟触发POI漏洞的执行环境
-
FUGIO利用分支覆盖率、运行时引用错误和模糊化过程中条件表达式中出现的提示,设计出更具前景的输入对象,从而在测试的POP链中找到更深层次的gadget
-
FUGIO分为哪五个模块?
-
POI检测器(POI检测器通过动态测试检测目标PHP应用程序中的潜在POI漏洞。具体来说,它会动态检测接收预定义输入字符串的注入点,并将其转换为PHP对象。)
-
静态分析器(静态分析器为用户定义的类和函数计算静态摘要,这些类和函数后来用于生成POP链和POP链标识符的PUT)
-
动态分析器(动态分析器计算动态生成的类和函数的函数摘要和类摘要,这些类和函数在目标应用程序源代码中没有静态定义。这些摘要随后也会被POP链标识符用于生成链和PUT)
-
POP链标识符(根据来自静态和动态分析器的信息,POP链标识符会发出一个可用POP链列表,并在执行模糊测试时使用。)
-
POP链Fuzzer(给定一个PUT和一个POP链,模糊器对PUT进行反馈驱动的模糊处理,生成利用对象。)
-
POI检测器何时会将调用报告为潜在的POI漏洞?
简而言之,当使用保存测试对象的实际参数调用其中一个内置函数时,检测器将此调用报告为潜在的POI漏洞,并将此调用站点信息传递给动态分析器。
-
POP链识别部分作者提出了一个比较naive的解决方法,并解释naive的原因:
方法:一个简单的解决方案是,从每个魔术方法对目标敏感接收器进行深度优先搜索,生成所有可行链。
原因:然而,从入口魔术方法遍历被调用者的下游可能不会遇到任何敏感的接收器,因此浪费了计算资源。此外,当调用链中存在循环时,算法不会终止。
-
POP链identifier将m的潜在调用者添加到叶子节点时,需要保证哪两点:
-
调用函数名称为m
-
实际参数的数量要和m的形参数量一致
-
FUGIO生成的PUT由哪两部分组成?
-
head:在头部部分,FUGIO设置动态分析器提供的所有环境和全局变量。
-
body:主体部分以包含所有定义文件,其中包含在利用目标POI漏洞时加载和可加载的所有gadget。主体部分以反序列化调用结束,该调用接受稍后fuzzer提供的序列化输入字符串
-
在fuzzing前,需要对于PUT进行插桩以获得哪三种反馈?
-
包含执行条件表达式和调用方法的执行跟踪
-
POP链中执行的小工具的数量
-
条件表达式中属性值的提示。
-
为了实现上面第一和第二的反馈,大致上怎么做?
设计FUGIO来插入代码,报告它们在每个函数条目上的执行情况,在每个条件表达式之前和之后,以及用户定义函数的每个调用语句。具体地说,每个被检测的代码会发出其行和文件的哈希值,从而留下一个执行注释。
-
为了实现第三种反馈,文章中提出了什么措施?
插装的代码报告常量和类型检查内置函数,如is_string()和is_int(),它们出现在执行的条件语句中。这些报告的常量和内置函数稍后用于生成属性值。作者将这种类型的属性生成称为属性提示。
-
在POP chain fuzzer中,需要存储种子执行结果的哪些内容
-
种子的选择次数
-
其属性树的哈希值
-
POP链中已执行gadget的最大深度。
-
生成注入对象需要:
-
设计多个类的结构层次结构,以反映给定的POP链
-
为这些多个类的属性分配适当的值,以方便攻击有效载荷到达sensitive sink
15. 变异策略:
-
当该类型为Object时,fuzzer随机从该属性的候选类中选择一个类
-
对于字符串、整数、布尔值和文件类型,模糊器将所选类型的一个随机值赋给该属性。
-
对于数组属性,模糊器随机设置数组大小,并为数组中的键和值分配随机值。
-
对于一个参考(reference)属性,模糊器识别它的所有者和静态和动态分析器计算的其他属性。然后它随机选择其他属性之一,并将其引用分配给目标引用属性。
16. Fuzzer利用了哪四种反馈信息?
-
分支覆盖
-
gadget达到的深度
-
属性提示
-
参考错误。
17. 为什么当POP链标识符为一个sink计算POP链时,FUGIO可以对由不同接收器生成的链发起模糊处理。
FUGIO并行运行POP链标识符和POP链模糊器。一旦POP链标识符在访问每个敏感接收器时计算出一组链,FUGIO通过调用每个链的fuzzing过程来管理fuzzing活动。
18. 从哪些方面来评估FUGIO的效果?
-
生成攻击对象的效率
-
与之前的开源工具效率进行对比
-
演示了几个参数影响功能利用的产生的程度
-
评估了FUGIO在发现之前未报告的POI漏洞及其漏洞利用方面的能力
19. 在评估时,有3个应用没有成功利用漏洞,简述原因:
-
在GLPI中,FUGIO没有任何发现,因为它实际上的确没有可利用的链。这意味着攻击者可以注入一个输入对象,但无法利用GLPI中的漏洞。
-
在vanilla forums中,FUGIO遗漏了一个触发LFI漏洞的可利用链。这是因为FUGIO不支持计算链的LFI sink。
-
在Yii中,FUGIO识别出可利用链,但模糊器不能为其生成利用对象。此利用的生成需要将包含适当索引及其对应类对象的数组值分配给该利用对象的属性。FUGIO无法在模糊超时内生成满足这些条件的利用对象。
20. 为什么FUGIO报告26个可开发链为PE链
-
FUGIO不会在PE链上执行利用oracle,因为攻击者不能以序列化字符串的形式注入文件资源。然而,作者发现九个PE链可以利用现有的fopen调用站点和注入的文件名。
-
只有当当注入有效载荷出现在目标接收器的实际参数中而没有任何损失时,exploit oracle才会报出E链。然而,即使在攻击者可以将攻击字符串部分注入参数的情况下,四个链也是可以利用的。
-
对于剩下的13个链,FUGIO无法在给定的模糊超时时间内精确定位注入攻击有效载荷的对象属性。
21. 在和Dahse的工具对比评估中,个别应用上FUGIO表现不佳,少找了一些E链,作者给出的原因?以及根源和可能的解决办法
-
四条链需要传递复杂的条件才能到达sink函数或控制这些sink函数的参数
-
两个链需要特定的操作系统环境和存在特定的文件或目录才能到达sink函数。
根源和解决方法:这些限制源自模糊测试的不健全本质;作者认为,更先进的模糊优化和计算资源将减少误报的数量。
22. 在34个已识别的链中,FUGIO为22个E链生成了攻击对象。缺失的链条有两个原因
-
其中的9条链,其中的几个属性拥有包含其他对象的数组值。因为这样的对象需要FUGIO为对象属性分配一个数组值,该数组值包含一个适当的索引及其对应的对象,FUGIO不能在给定的fuzzing时间内生成这些复杂的对象。
-
对于剩下的3条链,FUGIO没有进行模糊测试,因为没有足够的时间预算来测试其他链。
23. 为什么在实验中将fuzzing的timeout设置为100s?
作者将fuzzing超时设置为百分比大于70%的时间。对于可利用链,在100秒时百分比为70.1%,对于可能可利用链,在50秒时百分比为70.2%。因此,作者在所有实验中都将fuzzing timeout设置为100秒
24. 为什么在7.2中将POP最大链长设置为7?
最大链长由7变到8时,链数减少。这是因为模糊超时预算减少了所有有望生成攻击对象的链的模糊。因此,在§7.2中,作者将最大链长设为7。
25. limitation?
-
FUGIO也不能涵盖在枚举POP链时目标被调用者是静态不可确定的反射调用。
-
FUGIO有局限性。FUGIO只组装从目标PHP应用程序中提取的小工具,而不是从PHP内部类中提取的小工具。
文案:侯乔聃
排版:Amber
戳“阅读原文”即可查看论文原文哦~
复旦白泽战队
一个有情怀的安全团队
还没有关注复旦白泽战队?
公众号、知乎、微博搜索:复旦白泽战队也能找到我们哦~
原文始发于微信公众号(复旦白泽战队):白泽带你读论文 | FUGIO: Automatic Exploit Generation for PHP*