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

article/2025/4/17 6:15:38

渗透学习

不安全的反序列化之反序列化基础


文章目录

  • 渗透学习
  • 前言
    • *本文只做学习用途,严禁利用本文提到的技术进行非法攻击,否则后果自负,本人不承担任何责任。*
  • 一、序列化和反序列化
  • 二、PHP反序列化漏洞
    • 1.serialize()
    • 2.unserialize()
    • 3.反序列化漏洞
  • 总结


前言

本系列用于记录本人渗透学习的过程,主要内容围绕Owasp TOP 10展开。

不安全的反序列化之反序列化基础主要以PHP反序列化漏洞为例,理解不安全的反序列化的成因。为接下来反序列化引发的诸多场景介绍奠定基础。

本文只做学习用途,严禁利用本文提到的技术进行非法攻击,否则后果自负,本人不承担任何责任。

一、序列化和反序列化

序列化:把对象转换为字节序列,永久存到磁盘中。在网络中传输对象也要进行序列化。

反序列化:从磁盘中读取字节序列将它们反序列化成对象读出来。

简单来说:把对象转换为字节序列的过程称为对象的序列化;把字节序列恢复为对象的过程称为对象的反序列化。

序列化的目的是为了对象可以跨平台存储,和进行网络传输。而我们进行跨平台存储和网络传输的方式就是IO,而我们的IO支持的数据格式就是字节数组。

我们必须在把对象转成字节数组的时候就制定一个规则(序列化),那我们从IO流里读出数据的时候再以这种规则把对象还原回来(反序列化)

现在常见的序列化方式有:JDK(不支持跨语言)、JSON、XML、Hessian、Kryo(不支持跨语言)、Thrift、Protostuff、FST(不支持跨语言。

二、PHP反序列化漏洞

php反序列化漏洞,又叫php对象注入漏洞

php中有两个函数serialize()和unserialize()

1.serialize()

当在php中创建了一个对象后,可以通过serialize()把这个对象转变成一个字符串,保存对象的值方便之后的传递与使用

<?php
class chybeta{var $test = '123';
}$class1 = new chybeta;
$class1_ser = serialize($class1);
print_r($class1_ser);
?>

我们创建一个新的对象,并打印其序列化结果打印出来:

O:7:“chybeta":1:{s:4:"test";s:3:"123";}

这里的O代表存储的是对象(object),假如给serialize()传入的是一个数组,那它会变成字母a。7表示对象的名称有7个字符。"chybeta"表示对象的名称。1表示有一个值。{s:4:"test";s:3:"123";}中,s表示字符串,4表示该字符串的长度,"test"为字符串名称,之后类似。

2.unserialize()

unserialize()可以从已存储的表示中创建PHP的值,单就本次案例而言,它可以从序列化后的结果中恢复对象(object)。

<?php
class chybeta{var $test = '123';
}
$class2 = 'O:7:"chybeta":1:{s:4:"test";s:3:"123";}';	print_r($class2);
echo "</br>";
$class2_unser = unserialize($class2);
print_r($class2_ser);
?>

当使用unseriallize()恢复对象时,将调用_wakeup()成员函数。

3.反序列化漏洞

由此可得,当传给unserialize()参数可控时,我们可以通过传入一个精心构造的序列化字符串,从而控制对象内部的变量甚至是函数

首先我们先来了解PHP的魔术方法:
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(),__invoke(), __set_state(), __clone() 和 __debugInfo() 等方法在 PHP 中被称为"魔术方法"(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。

着重关注以下几个:
构造函数__construct():当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。
析构函数__destruct():当对象被销毁时会自动调用。
__wakeup() :如前所提,unserialize()时会自动调用。
__sleep() :在对象在被序列化之前运行
__toString() :在一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。

借用学习案例理解
在这里插入图片描述
在log.php中构建一个WTFLog 类,调用 loginfo 方法会记录一条记录到access.log文件中,当这个类完成它的使命的时候(exit),会删除掉filename对应的文件,现在是access.log。

设计一个存在反序列化漏洞的案例:
在这里插入图片描述
该代码的业务目标是从用户处收集序列化后的数据,前面的内容不存在问题,问题是直接使用客户端可以控制的输入点($_GET[‘pet_serialized’]),在不进行验证的情况下,直接实例化了这段代码。

接下来是危险注入点的利用方式(重新创建一个新的poc.php,把log.php中的WTFlog类引进来)。
在这里插入图片描述
index.php是我们设置的一个文件,会输出一句话:
在这里插入图片描述
运行poc.php,就可以得到我们想要序列化后的WTFlog字符串:
O:6:“WTFLog”:1:{s:8:“filename”;s:9:“index.php”;}
利用这个字符串,去调用pets.php
在这里插入图片描述
我们发现本来要删除掉的access.log文件,因为filename的更改删除了index.php
在这里插入图片描述
回顾一下整个漏洞利用的过程:
1.需要有一个漏洞触发点 pets.php 内的$pet = unserialize($_GET['pet_serialized']);
2.需要有一个相关联的,有魔术方法(会被自动调用)的类。log.php (WTFLog 内的__destruct函数)
3.漏洞的效果取决于__destruct 这个魔术函数内的操作,这里的是可以操控的可以删除的log 的 filename。
4.构建poc.php ,利用程序,先序列化后,从可控输入$_GET['pet_serialized']输入进去。

再看另一个学习案例
先创建一个类,并输出filename的值,最后输出序列化字符串:

<?phpclass F{public $filename='a.txt';
}$a = new F();
echo $a->filename.'<br />';
echo serialize($a);

输出结果:
在这里插入图片描述
再创建一个类,并输出filename的值,最后输出序列化字符串:

<?phpclass F{public $filenameF='bcda.txt';
}$a = new F();
echo $a->filenameF.'<br />';
echo serialize($a);

输出结果:
在这里插入图片描述
这两个代码定义的类一样, 只是属性不一样。
当我们使用以下代码反序列时:

<?phpclass F{public $filename='a.txt';function __destruct(){echo '--------------><br />';}
}$a = new F();
echo $a->filename.'<br />';
echo serialize($a);
$b = unserialize('O:1:"F":1:{s:9:"filenameF";s:8:"bcda.txt";}');
echo '<br />'.$b->filename;
echo '<br />'.$b->filenameF;

结果如图所示:
在这里插入图片描述
可以看到析构函数__destruct()输出了两次,说明a,b是同一类,a,b对象被销毁的时候分别执行了一次。只不过b多了一个属性filenameF。

我们可以利用自动执行某些函数或方法的特性,执行我们想要的操作:
创建如下代码(销毁对象时会读取文件中内容并输出):

<?phpclass F{public $filename='d:\\phpstudy\\www\\a.txt';#$filename为publicfunction __destruct(){$data = readfile($this->filename);echo $data;}
}$a = new F();
echo $a->filename.'<br />';

执行结果:
在这里插入图片描述
再衍生创建以下测试代码:

<?phpclass F{public $filename='d:\\phpstudy\\www\\a.txt';#$filename为publicfunction __destruct(){$data = readfile($this->filename);echo $data.'<br />';}
}$a = new F();
echo $a->filename.'<br />';
$b = unserialize($_GET[a]);

这代码中我们用unserialize反序列一个字符串变成一个类对象, 也就是说这个代码中, 会有两个类对象, 一个是 a , 一 个 是 用 户 可 控 的 a, 一个是用户可控的 a,b ($b 中的filename可控, 因为class F中的 filename为public)。

当代码运行结束时, 会运行两个析构函数。 第一次运行的析构函数中, filename为$a中默认的 ‘d:\phpstudy\www\a.txt’, 第二个因为是从$_GET[a]获得字符串, 所以我们可以控制第二个对象中的filename。

从而使得 __destruct 函数可以读取到我们想要读的文件。

构建一个类和上面代码的类相同的代码:

<?phpclass F{public $filename='a.txt';
}$a = new F();
$a->filename = 'd:\\phpstudy\\www\\2.txt';
echo serialize($a);

此代码修改了filename的值,并生成了序列化字符串:O:1:"F":1:{s:8:"filename";s:21:"d:\phpstudy\www\2.txt";}
2.txt里存储着我们想要得到的password

我们将这个会改变原有filename的值的代码的序列化字符串发送到测试代码中去:http://localhost/11.php?a=O:1:%22F%22:1:{s:8:%22filename%22;s:21:%22d:\phpstudy\www\2.txt%22;}
这样测试代码除了有对象 a 外 , 还 反 序 列 化 创 建 了 一 个 对 象 a外,还反序列化创建了一个对象 ab,而这个b中的属性filename已经被我们修改了。最后运行两次__destruct析构函数时,第一次读取了a.txt,另一次读取2.txt

总结一下反序列化漏洞出现的原因:

<?php
include "xxx.php";#此文件中有类定义, 有魔术函数或方法, 且输入参数能被控制
class Classname{#存在有害魔术函数或方法,且输入参数能被控制
}do something...
do something...
do something...#存在反序列化函数
unserialize('用户输入有害参数未过滤')
do something...
do something...
do something...

总结

以上介绍了序列化和反序列化,然后举了两个PHP反序列化漏洞的案例。案例都是因为使用了魔术函数和方法,而且存在没有进行过滤的反序列化函数,在对象被销毁时触发析构函数造成危险。接下来的反序列化的文章将会以一道CTF比赛的题目入手,通过代码审计发现反序列化漏洞并进行利用,加深对反序列化的理解。


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

相关文章

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;黑盒测试…

软件测试用例.范文,软件测试用例模板范文

软件测试用例模板范文 (8页) 本资源提供全文预览&#xff0c;点击全文预览即可全文预览,如果喜欢文档就下载吧&#xff0c;查找使用更方便哦&#xff01; 14.9 积分 XX 系统系统 测试用例测试用例 XX 系统-测试用例 1 由安博测试空间技术中心由安博测试空间技术中心 http://ww…

路由器与交换机知识总

路由器与交换机知识总结 路由器&#xff08;Router&#xff09;是一种计算机网络设备&#xff0c;提供了路由与转发机制&#xff0c;可以决定数据包从源到目的所经过的路径&#xff0c;这个过程就叫做路由&#xff1b;将路由器输入端的数据包交移到目的路由器&#xff0c;这个…