PHP反序列化命令执行及防范

article/2025/4/8 14:51:44

PHP反序列化命令执行

1、 序列化与反序列化原理

序列化(serialization)在计算机科学的数据处理中,是指将数据结构或对象状态转换成可取用格式(例如存成文件,存于缓冲,或经由网络中发送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。依照序列化格式重新获取字节的结果时,可以利用它来产生与原始对象相同语义的副本。序列化是一种将对象的状态信息转换为可以存储或传输的形式的过程(转化为信息流)。在序列化期间,对象将其当前状态写入到临时或持久性存储区以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

对于许多对象,像是使用大量引用的复杂对象,这种序列化重建的过程并不容易。面向对象中的对象序列化,并不概括之前原始对象所关系的函数。这种过程也称为对象编组(marshalling)。从一系列字节提取数据结构的反向操作,是反序列化。

序列化与反序列化为数据交换提供了可能,但是因为传递的是字节码,可读性差。在应用层开发过程中不易调试,为了解决这种问题,最 直接的想法就是将对象的内容转换为字符串的形式进行传递。具体的传输格式可自行定义,但自定义格式有一个很大的问题——兼容性,如果引入其他系统的模块,就需要对数据格式进行转换,维护其他的系统时,还要先了解一下它的序列化方式。为了统一数据传输的格式,出现了几种数据交换协议,如:JSON, Protobuf,XML。这些数据交换协议可视为是应用层面的序列化/反序列化。

2、 序列化与反序列化用法

JSON中的元素都是键值对——key:value形式,键值对之间以":“分隔,每个键需用双引号引起来,值的类型为String时也需要双引号。其中value的类型包括:对象,数组,值,每种类型具有不同的语法表示。json数据中地值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。对象是一个无序的键值对集合。以”{“开始,以”}“结束, 每个成员以”,"分隔。
首先我们需要创建类,随之才能对类进行序列化。创建类写法如下:

Class类名{变量1 = 参数1;变量2 = 参数2;变量3 = 参数3;方法1(){}方法2(){}
}

实例如下:

<?Php
Class student{Public $name = ‘xiaoming’Public $name = ‘20’Public $score = ‘60’
}
?>

上图定义了一个类student,该类含有三个变量:姓名、岁数和分数。无需对变量进行数据类型定义,直接进行赋值。不同变量之间用;分号隔开。
而对类进行序列化后输出的结果格式如下图,类含有的变类型要进行缩写,string字符型用s表示,Int数值型用i表示。而关于序列符号,参数与变量之间用;分号隔开,同一变量和同一参数之间用:冒号隔开。对象中只有变量,方法不会体现在序列化后的对象中:

O:对象名长度:“对象名”:对象成员变量个数:{变量1类型:变量名1长度:"变量名";参数1类型:参数1长度:"参数1";变量2类型:变量名2长度:“变量名2”;参数2类型:参数2长度:"参数2";... .. .}

通过serialize()函数对之前创建的student类进行序列化后输出结果如下:

O:7:"student":3:{s:4:"name";s:8:"xiaoming";s:3:"age"; :20;s:5:"score";i:60;}

序列化的原本意图是希望对一个Java对象作一下“变换”,变成字节序列,这样一来方便持久化存储到磁盘,避免程序运行结束后对象就从内存里消失,另外变换成字节序列也更便于网络运输和传播,所以概念上很好理解。而反序列化,则是把字节序列恢复为原先的Java对象。下面一张图能够帮助大家理解:
在这里插入图片描述
实际中我们可以通过php自带函数中的serialize()和unserialize()轻易实现序列化和反序列化。

序列化:serialize()
使用函数serialize()序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
反序列化:unserialize()
使用unserialize()函数对已序列化的变量进行操作,重新生成一个对象。

一起来分析下面这个完整案例从而了解下这序列化和反序列化这两个过程的写法和效果:
在这里插入图片描述
首先,创建示例类student,并输出该类序列化的结果:
在这里插入图片描述
对应上述代码的输出结果如下:
在这里插入图片描述
对上例的student序列化后的数据通过unserialize()进行反序列化:
在这里插入图片描述
输出反序列化结果如下:

Class student #2(3){Public $name => string(8) “xiaoming”Public $age => int(20)Public $score => int(60) 
}

从上述序列化和反序列化两个输出结果对比发现,序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。所以对象A和对象B序列化后并没有什么区别。unserialize()函数能够重新把字符串变回php原来的值。再多给几个例子对比:
在这里插入图片描述
序列化目的:
1、以某种存储形式使自定义对象持久化
比如说刚才的类里面保存着学生的个人信息,我想要将这些信息保存起来,以后可以随时取出来用,就可以采用序列化。将一个Word保存为docx,这就是序列化的过程。打开docx文档,显示内容,就是反序列化的过程。
2、将对象从一个地方传递到另一个地方
比如说在进行网络传输的过程中,发送数据和接收数据都是通过byte[]来获取的时候,如果你要发送一个对象,需要进行序列化。 然后接受数据的时候进行反序列化,还原对象。
3、使程序更具维护性
序列化可以将内存中的对象保存到本地文件和数据库中,大大提高了代码的可维护性。

3、 反序列化漏洞

漏洞的根源在于unserialize()函数的参数可控。如果反序列化对象中存在魔术方法,而且魔术方法中的代码有能够被我们控制,漏洞就这样产生了,根据不同的代码可以导致各种攻击,如代码注入、SQL注入、目录遍历等等。

3.1 魔术方法

PHP的类中可能会包含一些特殊的函数叫魔术函数,魔术函数命名是以符号__开头的。这些函数在某些情况下会自动调用,其中,反序列化漏洞主要由以下面魔术方法造成:

__construct():在对象创建时自动被调用;
__sleep():在对象序列化的时候自动被调用;
__destruct():在脚本运行结束时自动被调用;
__wakeup():在反序列化为对象时自动被调用;
__toString(): 直接输出对象引用时自动被调用。

接下来,详细的展示下上述几种常见的魔术方法和他们的调用场景。

__sleep():在对象序列化的时候自动被调用

某类中存在__sleep()函数,当所处类被进行序列化成为对象时,__sleep()函数就会被自带调用,从而执行__sleep()函数中的语句。

在这里插入图片描述
__sleep()函数中的echo语句在serialize($student)时被执行了从而打印在页面上:
在这里插入图片描述

__wakeup():在反序列化为对象时被调用

某类中存在__wakeup()函数,当所处类被反序列化时,__wakeup()函数就会被自带调用,从而执行__wakeup()函数中的语句。

在这里插入图片描述
__wakeup()函数中的echo语句在unserialize($a)时被执行了从而打印在页面上:
在这里插入图片描述

__destruct():在对象销毁前被调用

某类中存在__destruct()函数,当对象销毁前,__destruct()函数就会被自带调用,从而执行__destruct()函数中的语句。每个对象在所有代码执行结束时都会进行销毁。

在这里插入图片描述
__destruct()函数中的echo语句在所有代码执行结束后被执行了从而打印在页面上:
在这里插入图片描述

__toString():直接输出对象引用时自动被调用

某类中存在__toString()函数,当对象被直接输出时,__toString()函数就会被自带调用,从而执行__toString()函数中的语句。

在这里插入图片描述
__toString()函数中的echo语句在echo $student对象直接被输出时被执行了从而打印在页面上:
在这里插入图片描述

3.2 反序列化漏洞利用

上面介绍了多种魔术方法,具体反序列化漏洞的利用方式我们通过分析实际案例来掌握。

案例1

漏洞举例:反序列化导致任意文件读取。
在这里插入图片描述
上图是源码本意是输出错误日志代码,读取error.log文件内容。FileClass类中有魔术方法__toString(),方法中的语句是利用file_get_content()函数读取变量filename中的内容。由此可见,如果我们可以控制变量filename的值从而传入任意文件名,就可以读取任意文件内容。重点在后面的 o b j = u n s e r i a l i z e ( obj=unserialize( obj=unserialize(_GET[‘file’]),既然这边存在反序列化函数,并随之echo $obj语句执行时就会自动调用__toString()函数,那么我们便可以手动构造一个序列化的对象FileClass修改该对象中的filename变量值为目标文件名,将构造好的对象放入URL通过GET方式提交表单,从而在其对象进行反序列化后实现指定文件读取。
以读取当前目录下的1.txt文件为例构造对象:

Class FileClass{Public $filename = ‘1.txt’;
}
构造对象时无需声明方法,只需要声明变量及变量值即可。上图进行序列化后获得对象:
O:9:“FileClass”:1:{s:8:”filename”;s:5:”1.txt”}
获得对象后将其作为file参数值添加到URL中:
http://127.0.0.1/unserialize. php?file=
0:9:"FileClass" :1:{s:8:"filename";s:5:"1.txt";}
成果展示,成功读取当前目录下的1.txt:

在这里插入图片描述

案例2

反序列化漏洞的根源在于unserialize()函数的参数可控。如果反序列化对象中存在魔术方法,而且魔术方法中的代码有能够被我们控制,漏洞就这样产生了,根据不同的代码可以导致各种攻击,如代码注入、SQL注入、目录遍历等等。漏洞代码如下:
在这里插入图片描述
上图中漏洞代码使用了php的魔术方法__destruct(),而destruct()是当一个对象被销毁时被自动调用的析构方法。然后unserialize()中参数可控,这样我们就可以构造一个序列化的对象A来控制其中的变量a的值,最终会产生漏洞。
以上边的漏洞代码为例,我们需要构造一个序列化的对象A并给其中变量a赋值为<?php phpinfo();?> 如下:
在这里插入图片描述
这个时候,就会向hello.php文件中写入<?php phpinfo();?>:
在这里插入图片描述
通过这个思路还可以写入一句话木马然后实现远程连接get webshell。

命令执行漏洞防范

1、尽量少用执行命令的函数或者直接禁用;
system()、assert()、shell_exec()、passthru()等命令执行函数。
2、尽量不要执行外部命令;
尽量使用自定义函数或函数库实现外部应用程序或命令的功能。在执行system、eval等命令执行功能的函数前,要确认参数内容。
3、使用自定义函数或者函数库来代替外部命令的功能;
4、参数值尽量使用引号包括,并在拼接前调用addslashes函数进行转义;
5、在使用动态函数之前,确保使用的函数是指定的函数之一;
6、在进入执行命令的函数方法之前,对参数进行过滤,对敏感字符进行转义;
7、使用safe_mode_exec_dir执行可执行的文件路径;
将php.ini文件中的safe_mode设置为On,然后将允许执行的文件放入一个目录,并使用safe_mode_exec_dir指定这个可执行的文件路径。这样,在需要执行相应的外部程序时,程序必须在safe_mode_exec_dir指定的目录中才会允许执行,否则执行将失败。
8、对于可控点是程序参数的情况下,使用escapeshellcmd函数进行过滤,对于可控点是程序参数值的情况下,使用escapeshellarg函数进行过滤。escapeshellarg函数会将用户引起参数或命令结束的字符进行转义,如单引号“’”会被转义为“’”,双引号““”会被转义为“””,分号“;”会被转义为“;”,这样escapeshellarg会将参数内容限制在一对单引号或双引号里面,转义参数中包括的单引号或双引号,使其无法对当前执行进行截断,实现防范命令注入攻击的目的。


http://chatgpt.dhexx.cn/article/PFF740q2.shtml

相关文章

PHP反序列化魔术方法

目录 __construct __destruct __call __get __set __isset __unset __sleep __wakeup __toString __invoke PHP讲以双下划线__保留为魔术方法&#xff0c;所有的魔术方法 必须 声明为 public。 __construct()&#xff0c;类的构造函数 __destruct()&#xff0c;类的析…

PHP反序列化详解(一)——反序列化基础

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是PHP反序列化详解&#xff08;一&#xff09;——反序列化基础。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#x…

php反序列化姿势学习

php反序列化姿势学习 1.__wakeup()函数绕过2./[oc]:\d:/i研究php反序列化逃逸1.替换后字符串增加2.替换后字符串减少 1.__wakeup()函数绕过 wakeup函数作为php反序列化中的一个函数&#xff0c;也经常被拿来当做考点&#xff0c;比如这样 function __wakeup() { if ($this->…

【web漏洞】PHP反序列化

目录 知识点反序列化常用方法&#xff1a;序列化的&#xff08;构造payload&#xff09;运行顺序反序列化的&#xff08;实现payload&#xff09;运行顺序绕过__wakeup()__tostring() 知识点 序列化&#xff08;serialize&#xff09;&#xff1a; 对象的状态信息转换为可以存…

PHP反序列化CTF例题

渗透学习 不安全的反序列化之PHP反序列化 文章目录 渗透学习前言*本文只做学习用途&#xff0c;严禁利用本文提到的技术进行非法攻击&#xff0c;否则后果自负&#xff0c;本人不承担任何责任。* 一、CTF例题二、PHP反序列化漏洞和XSS跨站脚本总结 前言 本系列用于记录本人渗…

php反序列化漏洞

php反序列化漏洞 关于php面向对象编程&#xff1a; 对象&#xff1a;可以对其做事情的一些东西。一个对象有状态、行为和标识三种属性。 类&#xff1a;一个共享相同结构和行为的对象的集合。 每个类的定义都以关键字class开头&#xff0c;后面跟着类的名字。一个类可以包含有…

PHP反序列化漏洞总结

文章目录 一、 基础知识1、什么是反序列化漏洞:序列化与反序列化&#xff1a;1、序列化&#xff1a;2、反序列化&#xff1a; 二、PHP魔法函数1、常见方法:2、安全问题&#xff1a; 三、CTF中的反序列化例题一&#xff1a;例题二&#xff1a; 四、靶场练习1、反序列化触发XSS&a…

通过简单案例接触PHP反序列化

渗透学习 不安全的反序列化之反序列化基础 文章目录 渗透学习前言*本文只做学习用途&#xff0c;严禁利用本文提到的技术进行非法攻击&#xff0c;否则后果自负&#xff0c;本人不承担任何责任。* 一、序列化和反序列化二、PHP反序列化漏洞1.serialize()2.unserialize()3.反序…

php反序列化--字符串逃逸

php反序列化–字符串逃逸 PHP反序列化的字符串逃逸&#xff0c;一共分有两种情况&#xff0c;情况一&#xff1a;过滤后字符串变多&#xff0c;情况二&#xff1a;过滤后字符变少(本篇文章默认已有反序列化相关知识基础) 过滤后字符串变多 以ctfshow-web262为例讲解&#xf…

php反序列化漏洞(一)

PHP反序列化漏洞就是PHP对象注入 序列化&#xff1a;serialize 反序列化&#xff1a;unserialize 序列化其实就是将数据转换成可逆的数据结构&#xff0c;这种数据结构可认为是字符串。可逆的过程则为反序列化。 那么序列化有什么作用&#xff1f; 方便储存和传输。在PHP中…

php反序列化字符逃逸

前言 在了解php反序列化漏洞后&#xff0c;我又进一步学习了字符逃逸的相关内容。这一部分相对来说是比较难理解的。我也是在网上看了很多篇文章&#xff0c;再次自己总结一下究竟什么是字符逃逸&#xff0c;也方便日后复习。 字符逃逸的原理 什么是字符逃逸&#xff0c;从字…

php反序列化[基础]

基础 概述 序列化:把复杂的数据类型压缩到一个字符串中 数据类型可以是数组&#xff0c;字符串&#xff0c;对象等 函数 : serialize() 反序列化:恢复原先被序列化的变量 函数: unserialize() serialize()函数用于序列化对象或数组&#xff0c;并返回一个字符串 据访问修饰…

PHP中序列化与反序列化

PHP序列化&#xff1a;serialize 序列化是将变量或对象转换成字符串的过程。 举例&#xff1a; <?php class man{public $name;public $age;public $height;function __construct($name,$age,$height){ //_construct&#xff1a;创建对象时初始化$this->name …

(37)【PHP反序列化】PHP反序列化原理、函数、利用过程

目录 一、简介&#xff1a; 二、原理&#xff1a; 2.1、函数&#xff1a; 2.1.1、serialize()序列化 2.1.2、unserialize()反序列化 三、常见的序列化格式&#xff1a; 四、产生的原因&#xff1a; 4.1、无类&#xff1a; 4.2、有类&#xff1a; 五、魔术方法&#x…

php反序列化总结

php反序列化总结 基础知识 序列化 序列化就是将 对象object、字符串string、数组array、变量 转换成具有一定格式的字符串&#xff0c;方便保持稳定的格式在文件中传输&#xff0c;以便还原为原来的内容。 serialize ( mixed $value ) : stringserialize() 返回字符串&…

PHP反序列化入门手把手详解

PHP反序列化入门手把手详解 前言:文章内容大致可分为原理详解-漏洞练习- 防御方法。文章内容偏向于刚接触PHP反序列化的师傅,是一篇对PHP反序列化入门的手把手教学文章。文章特色在于对PHP反序列化原理的详细分析以及一系列由简入深的PHP反序列化习题练习和分析讲解。文章写作初…

[CTF]PHP反序列化总结

文章目录 PHP反序列化这一篇就够了简介常见的序列化格式案例引入反序列化中常见的魔术方法反序列化绕过小Trickphp7.1反序列化对类属性不敏感绕过__wakeup(CVE-2016-7124)绕过部分正则利用引用16进制绕过字符的过滤PHP反序列化字符逃逸情况1&#xff1a;过滤后字符变多情况2&am…

测试用例介绍

测试用例 用例介绍 定义 为某个业务目标而编制的一组由测试输入&#xff0c;执行条件以及预期结果组成的案例。 为什么要学习测试用例&#xff1f; 再开始测试之前设计好测试用例&#xff0c;可以避免盲目测试并提高测试效率。测试用例的使用令软件测试的实施突出重点、目…

软件测试的测试用例应该怎么编写和模板

这个是软件测试的模板下面是软件测试的一些测试点和测试方法 硬件测试方法: 1.界面测试 2.性能测试(压力测试、稳定性测试) 3.恢复性测试 4.兼容性测试 5.安全性测试 6.破坏性测试 7.可用性测试 8.易用性测试 9.功能操作测试 软件测试: loading:加载中。 可视化页面可操作元素…

测试用例模板

测试用例模板 文章目录 前言1.文件原地址2.测试用例模板1.测试用例模板012.测试用例模板023.测试用例模板034.测试用例模板045.测试用例模板05 2上线回归测试1.回归测试检查表01 3.其他见过的模型参考关键词链接 前言 这个是模仿别人的模板来进行补充的。有些是不需要的&…