上次我们讨论了如果PHP的 unserialize() 函数让攻击者控制用户的输入,它将导致严重的漏洞,重温下大致概念,简单讲就是当攻击者控制传递给unserialize() 的序列化对象时,他可以控制所创建对象的属性。然后,通过控制传递给 _wakeup() 之类的magic方法的值,让攻击者有机会劫持应用程序流。
但是这方法也非百试百灵,举个栗子:如果该类声明的magic方法在开发方面不包含任何有用的代码,那该怎么办呢?很可惜攻击者还有其他方法,即使magic方法本身无法被利用,攻击者仍可能使用称为POP链的东西造成严重破坏。
POP 代表面向属性的编程,该名称来自于攻击者可以控制反序列化对象所有属性的事件。为了更好理解,他类似于ROP攻击(面向返回的编程),POP链通过将攻击代码脚本链接在一起来工作,以实现攻击者的最终目标。
> 关于POP学习的知识,可以参阅文末链接。
到这里,我们提到了POP链使用magic方法作为初始脚本,然后再调用其他脚本。发个例子仅供参考:
在示例中,可以看到我们定义了两个类:Example和CodeSnippet
其中 Example具有一个名为obj的属性,当对Example对象进行反序列化时,将调用其_wakeup() 函数,并调用obj的validate () 方法。
而 CodeSnippet 类具有一个名为code的属性,该属性包含要执行的代码字符串,以及一个validate() 方法,该方法对字符串调用 eval()。接下来,该程序会从用户那里获取POST参数数据,然后对数据调用unserialize()。
这些准备工作完成后,攻击者可以使用以下代码来生成注入的序列化对象:
接着我来解释下该代码块的作用:
1.定义一个名为CodeSnippet的类,并将其代码属性设置为“ phpinfo();”
2.定义一个名为Example的类,并在实例化时将其obj属性设置为新实例,再将其设置为新的CodeSnippet实例。
3.创建一个Example实例,将其序列化。
然后,攻击者可以将生成的字符串输入到POST参数数据中,接下来程序开始执行:
1.反序列化对象,创建一个Example实例。
2.调用_wakeup()函数,将obj属性设置为CodeSnippet实例。
3.调用 obj 的evaluate() ,运行eval(“phpinfo();”)
现在,通过上面的方法,攻击者可以通过POP链接和调用应用程序代码库中的代码来实现RCE攻击。
References:
https://blog.szfszf.top/tech/php-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96pop%E9%93%BE%E7%9A%84%E6%9E%84%E9%80%A0%E4%B8%8E%E7%90%86%E8%A7%A3/
http://redteam.today/2017/10/01/POP%E9%93%BE%E5%AD%A6%E4%B9%A0/
https://medium.com/swlh/diving-into-unserialize-more-than-rce-d48d371db7da