前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PHP函数unserialize()漏洞浅析

PHP函数unserialize()漏洞浅析

作者头像
字节脉搏实验室
发布2020-09-25 17:51:21
2.1K0
发布2020-09-25 17:51:21
举报
文章被收录于专栏:字节脉搏实验室

简单提一下,PHP的unserialize()函数采用一个字符串并将其转换回PHP对象。

一般情况下,当需要存储PHP对象或通过网络传输它时,首先要使用serialize()打包。

serialize(): PHP object -> plain old string that represents the obj

之后当再次使用该数据时,可以使用unserialize()函数解包并获取所需的数据。

unserialize(): string containing object data -> original object

我们可以查询PHP官方文档,从中可以了解到unserialize()从存储的表示形式创建PHP值,并采用单个序列化变量,最后将其转换回PHP值。

它带有两个参数:str和options。

str是包含加载反序列化的序列化字符串的参数。

options是包含控制某些功能行为的选项的数组。

特别是在unserialize()中,唯一有效的用户定义选项为allowed_classes. allowed_classes用来指定接收的类名称。

接下来,我将进一步研究allowed_class。

注:事实上,当unserialize()遇到不被接受的类对象时,该对象将被实例化为 _PHP_Incomplete_Class。

运作流程:

1.magic 方法

magic 方法是PHP中具有 magic 属性的函数名称。

具体与之相关的有两种,_wakeup()和_destruct()。此时,如果序列化对象的类实现了以上两种方法之一,则在对类的对象调用unserialize()时,这些方法将自动执行。

接着就要提到反序列化先决条件,在PHP中序列化对象时,serialize() 会将所有属性保存在该对象中。但是它不会存储对象类的方法,而只会存储类的名称。因此,为了取消序列化对象,必须预定义或自动加载对象的类。换句话说,该类的定义需要存在于你将对象反序列化unserialize()的项目文件中。

如果没有在该项目文件中定义该类,则该对象将被实例化为_PHP_Incomplete_Class,此刻它不具备任何方法,并且该对象实际上是无效的。

2.对象实例化

实例化是程序在内存中创建类的实例时,利用unserialize()所实现的。它采用序列化的字符串,该字符串指定要创建的对象的类以及该对象的属性。使用该字符串数据,unserialize()创建原始序列化对象的副本。然后它会检索程序中名为_wakeup()的函数,并在为该类定义的函数中执行相关代码。因为调用_wakeup()可以重建对象可能具有的任何资源,所以它通常被用于重建在序列化过程中可能丢失的数据库链接,并执行其他初始化任务。

3.程序执行

程序可以对对象进行一系列的操作,并使用它执行其他操作。入,宽字节注入依旧会产生:

4.对象销毁

函数的相关执行流程已经大致介绍完毕,那具体的unserialize()中的漏洞是如何发生的呢?

当攻击者控制传递给unserialize() 的序列化对象时,他可以控制所创建对象的属性。然后,通过控制传递给自动执行的方法,如_wakeup()的值,这将使攻击者有机会劫持应用程序流。

这被称为PHP对象注入。根据对象在程序发生的位置,PHP对象注入可以导致代码执行,SQL注入,路径遍历或DoS。

例如,请考虑以下易受攻击的代码片段:

攻击者可以使用此反序列化漏洞来实现RCE攻击,因为用户提供的对象被传递给反序列化,并且Example2类具有在用户提供的输入上运行 eval() 的魔术函数。

要利用此RCE,攻击者只需将其数据 cookie 设置为一个序列化的Example2对象,并将hook属性设置为他想要执行的任何PHP代码。他可以使用以下代码片段生成序列化的对象:

然后将上面生成的字符串传递到数据 cookie中将导致phpinfo() 被执行。一旦攻击者将序列化的对象传递到程序中,将引起以下问题:

攻击者将序列化的Example2对象作为数据 cookie 传递到程序中;

该程序在数据 cookie 上调用unserialize();

因为数据 cookie是序列化的Example2对象,所以unserialize()实例化一个新的Example2对象;

unserialize() 看到Example2类执行了_wakeup(),因此调用了_wakeup()。

_wakeup() 寻找对象的hook属性,如果它不是NULL,它将运行eval($hook)),但hook不是NULL,并设置为“ phpinfo();”,则执行eval(“phpinfo();”)

可以实现RCE。

那么知道了漏洞的形成,如何防范unserialize()漏洞呢?

为了防止发生PHP对象注入,建议不要将不受信任的用户输入传递给unserialize()。考虑使用JSON与用户之间传递序列化数据,如果确实需要将不受信任的序列化数据传递到unserialize(),请确保实施严格的数据验证,以最大程度地降低严重漏洞的风险。

References:

https://www.php.net/manual/en/function.unserialize.php

https://www.php.net/manual/en/language.oop5.magic.php

https://medium.com/swlh/diving-into-unserialize-3586c1ec97e

https://www.owasp.org/index.php/PHP_Object_Injection

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-09-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 字节脉搏实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档