文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

【反序列化漏洞-02】PHP反序列化漏洞实验详解

2023-09-21 11:44

关注

为什么要序列化

百度百科上关于序列化的定义是,将对象的状态信息转换为可以存储或传输的形式(字符串)的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区(非关系型键值对形式的数据库Redis,与数组类似)。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

  1. 在PHP中,每个类的定义都以关键字class开头,后面不仅跟着类名还跟着一对花括号,里面包含有类的属性与方法的定义。

  1. 一个类可以包含有属于自己的属性(常量:值变量的值不会改变、变量)和方法(函数)。

  1. 由于类的实例化对象比较抽象,不方便用于传输和存储。

tips:类为class,对象是object;举例来说就是,动物为一个大类,大类之后再分小一类如猫猫或者狗狗;而具体的某个动物就为一个对象。一个对象就相当于一个变量,对象是一种语言结构。

简单来说,序列化就是把一个对象变成可以传输的字符串(字符串便于传输,只需要把字符串赋给变量即可)。在传递和保存对象时,为保证对象的完整性和可传递性,程序将对象转换为有序字节流,以保存在本地文件中,可以以特定的格式在进程之间跨平台、安全的进行通信。(比如从java平台传递到php平台)反序列化则根据字符串中保存的对象状态及描述信息,通过反序列化重建对象

序列化的优点

实际上用Redis数据库作为缓存,一般用于存储序列化后的字符串,待字符串需要使用时,再反序列化为对象,方便调用。

PHP中的序列化与反序列化

反序列化漏洞并不是PHP特有,也存在于Java、Python等语言之中,但其原理基本相通。

序列化与反序列化的定义

PHP中的序列化与反序列化,基本都是围绕serialize()unserialize()两个函数展开的。在介绍这两个函数之前,我们可以先看一个简单的例子。

简单的例子

我们可以用json格式数据的编码与解码(json格式就是格式化的字符串,也就是说json格式的数据,它具备一定的格式),来理解序列化与反序列化的过程。虽然json数据与反序列化漏洞没有什么关系,但是这个例子有助于我们理解。代码内容如下:

'AJEST','age'=>18,'SEX=>true','score'=>89.9);// echo不能直接输出数组,但是如果把$student给做一个json_encode 的格式转换,就可以用echo来输出echo $student;echo "
";$student_json=json_encode($student);echo $student_json;?>

我们定义一个数组,数组属于抽象的数据结构,为了方便跨平台传输数据,可以将其进行json编码。json格式的数据是以键值对的形式出现的。类似于这种格式的数据易于处理易于传输。结果如下

序列化与反序列化Demo

序列化会将一个抽象的对象转换为字符串。

  1. 我们可以写一个Demo来说明序列化的过程,首先创建一个类,代码内容如下:

  1. 类名是student,该类中有四个变量。接下来,我们可以将这个类实例化,也就是创建一个对象(new),并给对象中变量赋值。代码如下:

name = "wyy";$student1->sex = false;$student1->age = 20;$student1->score = 95;?>
  1. 最后我们使用serialize(),将$student1这个对象序列化成一个字符串。这样的字符串就很容易传输和存储了。如下:

name = "wyy";$student1->sex = false;$student1->age = 20;$student1->score = 95;// 创建对象2$student2 = new student();$student2->name = "xcc";$student2->sex = true;$student2->age = 25;$student2->score = 98;// 输出wyy和xcc的成绩echo $student1->name."'s score = ".$student1->score;// 进行换行echo "
";echo $student2->name."'s score = ".$student2->score;// 用var_dump输出对象echo "
";var_dump($student1);var_dump($student2);// 对对象进行序列化并输出echo "
";echo "序列化后采用echo输出
";echo serialize($student1);?>
  1. 打开浏览器访问该文件,显示如下,可以看到对象被序列化成字符串:

  1. 同样,我们可以使用unserialize()函数,将字符串反序列化成为一个对象。由于字符串中含有双引号,所以此处可以使用定界符的方法定义字符串。代码如下:

name = "wyy";$student1->sex = false;$student1->age = 20;$student1->score = 95;// 创建对象2$student2 = new student();$student2->name = "xcc";$student2->sex = true;$student2->age = 25;$student2->score = 98;// 输出wyy和xcc的成绩echo $student1->name."'s score = ".$student1->score;// 进行换行echo "
";echo $student2->name."'s score = ".$student2->score;// 用var_dump输出对象echo "
";var_dump($student1);var_dump($student2);// 对对象进行序列化并输出echo "
";echo "
";// 序列化后采用echo输出echo serialize($student1);$str =<<";var_dump(unserialize($str));?>

综上,序列化→我们将对象序列化成字符串,反序列化→我们将字符串反序列化成对象

  1. 运行这个脚本文件,我们可以看到反序列化后的对象

PHP反序列化漏洞

PHP反序列化漏洞也叫php对象注入,是一个非常常见的漏洞,这种类型的漏洞虽然有些难以利用,但一旦利用成功就会造成非常危险的后果。

漏洞的形成的根本原因程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、getshell等一系列不可控的后果

PHP中的序列化与反序列化,基本都是围绕serialize()unserialize()两个函数展开的。

实验步骤

实验一

  1. 在网站根目录新建Code文件夹,在Code文件夹中新建PHP文件夹,再从PHP文件夹中新建Class文件夹,最后在Class文件夹下新建文件unserialize.php,文件内容如下:

str);}}// 创建对象并序列化后输出$test =new Test();echo serialize($test);echo "
";$t = serialize($test);var_dump(unserialize($t));?>
  1. 打开浏览器访问该文件,显示如下

  1. 如下修改文件内容

str);}}//创建对象并序列化后输出$test = new test();echo "序列化后采用echo输出:
";echo serialize($test1);echo "
";//输入序列化后的字符串,并采用凡序列化后采用var_dump输入$obj=$_GET['obj'];echo "反序列化后采用var_dump输出:
";var_dump(unserialize($obj));?>
  1. 继续打开浏览器访问该文件,输入参数?obj=?obj=O:4:"test":1:{s:3:"str";s:5:"hello";},网页内容显示如下,含有两句“ This is function __destruct()”,说明函数被调用两次。注意,当销毁实例化类(对象)的时候,__destruct()函数会被自动调用

  1. 接下来修改参数?obj=O:4:"test":1:{s:3:"str";s:10:"phpinfo();";},网页显示如下,可以看到phpinfo()函数被成功执行。

由以上代码,我们会发现,PHP的反序列化漏洞学院与其他漏洞配合,如代码执行SQLi等。

我们输入的phpinfo()为何会作为PHP语句运行呢?

我们观察代码,发现在类中有一个函数_destruct()并且这个函数调用的eval语句,执行$this->str变量。为什么_destruct()没有被调用,函数内的语句就会被执行呢?

我们发现,当销毁实例化类(对象)的时候,_destruct()函数会被自动调用,并输出字符串[This is function_destruct()]。

实验二

  1. unserialize.php文件修改如下,将new新建test类对象的语句注释掉,再次实验

str);}}//创建对象并序列化后输出//$test1 = new test();//echo "序列化后采用echo输出:
";//echo serialize($test1);echo "
";//输入序列化后的字符串,并采用凡序列化后采用var_dump输入$obj=$_GET['obj'];echo "反序列化后采用var_dump输出:
";var_dump(unserialize($obj));
  1. 在浏览器中输入参数?obj=?obj=O:4:"test":1:{s:3:"str";s:5:"hello";},网页显示如下,含有1句"This is function_destruct()",说明函数被调用1次,注意,当销毁实例化类(对象)的时候,__destruct()函数会被自动调用

  1. 继续在浏览器中输入?obj=O:4:"test":1:{s:3:"str";s:10:"phpinfo();";},网页显示如下,可以看到同样能执行phpinfo()函数,因此可以判断输入对象成功反序列化为test类对象,并自动执行了__destruct()函数

实验三

  1. unserialize.php文件修改将最后一行语句修改如下,实验如下

str);}}//创建对象并序列化后输出//$test1 = new test();//echo "序列化后采用echo输出:
";//echo serialize($test1);echo "
";//输入序列化后的字符串,并采用凡序列化后采用var_dump输入$obj=$_GET['obj'];//echo "反序列化后采用var_dump输出:
";//var_dump(unserialize($obj));$obj1=unserialize($obj);?>
  1. 浏览器同样输入参数?obj=O:4:"test":1:{s:3:"str";s:5:"hello";},网页显示如下,含有1句“ This is function __destruct()”,说明函数被调用1次。

  1. 浏览器同样输入参数?obj=O:4:"test":1:{s:3:"str";s:10:"phpinfo();";}访问,,网页显示如下,可以看到同样能执行phpinfo()函数,因此可以判断输入对象成功反序列化为test类对象,并自动执行了__destruct()函数。

tips:

PHP魔术方法归纳

以[_]开头的方法,是PHP中的魔术方法,类中的魔术方法,在特定情况下会被自动调用。主要魔术方法及其触发条件如下。

魔术方法

触发条件

_construct()

构造方法,当一个对象被创建时调用

_destruct()

析构方法,PHP将在对象被销毁前(即从内存中清除前)调用

_autoload()

使用尚未被定义的类时自动调用。通过此函数,脚本引擎在PHP出错失败前有了最后一个机会加载所需的类。

_call($method,$arg_array)

在对象中调用一个不可访问方法时

_callStatic()

在静态上下文中调用一个不可访问的方法时使用

_clone()

使用clone方法复制一个对象时

_invoke()

当尝试调用函数的方式调用一个对象时,_invoke方法会被自动调用

_get($property)

从不可访问的属性中读取数据

_set($property,$value)

给一个未定义的属性赋值时调用

_isset($property)

在一个未定义的属性上调用isset()函数时调用此方法

_unset($property)

在一个未定义的属性上调用unset()函数时调用此方法

_toString()

在将一个对象转化成字符串时自动调用

_sleep()

序列化对象前调用(其返回需要是一个数组)

_wakeup()

反序列化恢复对象前调用

_set_state()

当调用var_export()时,这个静态方法就会被调用

注意:

  1. serialize() 检查类中是否有魔术名称 __sleep 的函数。如果这样,该函数将在任何序列化之前运行。它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。

  1. 使用 __sleep 的目的是关闭对象可能具有的任何数据库连接,提交等待中的数据或进行类似的清除任务。此外,如果有非常大的对象而并不需要完全储存下来时此函数也很有用。

  1. 相反地,unserialize() 检查具有魔术名称 __wakeup 的函数的存在。如果存在,此函数可以重建对象可能具有的任何资源。

  1. 使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。

来源地址:https://blog.csdn.net/2301_76334474/article/details/129310127

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯