【web漏洞】PHP反序列化

article/2025/4/8 15:47:01

目录

    • 知识点
    • 反序列化常用方法:
    • 序列化的(构造payload)运行顺序
    • 反序列化的(实现payload)运行顺序
    • 绕过__wakeup()
    • __tostring()

知识点

  • 序列化(serialize): 对象的状态信息转换为可以存储或传输的形式的过程 在序列化期间,对象将当前的状态写入到临时或持久性的存储区【将状态信息保存为字符串】。
  • 反序列化(unserialize): 将字符串转换为状态信息 序列化 <—>反序列化。
  • 构造POP链:通过用户可控的反序列化操作,其中可触发的魔术方法为出发点,在魔术方法中的函数在其他类中存在同名函数,或通过传递,关联等可以调用的其他执行敏感操作的函数,然后传递参数执行敏感操作,即

用户可控反序列化→魔术方法→魔术方法中调用的其他函数→同名函数或通过传递可调用的函数→敏感操作

  • PHP反序列化只能修改成员变量的值和构造方法,其他的代码区不能修改
  • (1)属性声明是由关键字public,protected或者private开头,然后跟一个普通的变量声明来组成。 属性中的变量可以初始化,但是初始化的值必须是常量。所以修改属性值时,不能修改成属性=对象。

序列化的内容只有类名和成员变量,所以可控点是,类名和成员变量的值。
通过控制类名、可以指定反序列化的类,通过控制变量的值,就可以影响代码执行流程。然后按照我们的期望,将这些“影响”连接在一起,就可以控制代码的执行。

  • 序列化之后的字符串构成:
    序列化的内容只有类名和成员变量 成员方法不会被序列化

  • 在序列化时,会执行构造函数,所以就可以通过构造函数来控制各属性的值,得到我们想要属性值然后序列化这些属性值

在这里插入图片描述多加了几个方法,最后输出的还是一样的:
在这里插入图片描述但是添加构造方法之后,序列化的值就改变了,因为序列化的过程会新建对象,新建对象就会调用构造函数:
在这里插入图片描述

<?php
class key{public $a="abc";public $b=123;public function __construct(){$this->a="flag{123456}";$this->b=new key1();}
}
class key1{}
echo serialize(new key());
//O:3:"key":2:{s:1:"a";s:12:"flag{123456}";s:1:"b";O:4:"key1":0:{}}
类型结构
Strings:size:value;
Integeri:value;
Booleanb:value;(保存1或0)
NullN;
Arraya:size:{key definition;value definition;(repeated per element)}
ObjectO:strlen(object name):object name:object size:{s:strlen(property name):property name:property definition;(repeated per property)}
  • 想象自己是一个特工,你的目标是监控一个重要的人,有一天你怀疑目标家里的窗子可能没有关,于是你上前推了推,结果推开了,这是一个POC。之后你回去了,开始准备第二天的渗透计划,第二天你通过同样的漏洞渗透进了它家,仔细查看了所有的重要文件,离开时还安装了一个隐蔽的窃听器,这一天你所做的就是一个EXP,你在他家所做的就是不同的Payload,就把窃听器当作Shellcode吧!

反序列化常用方法:

__wakeup() //执行unserialize()时,先会调用这个函数
__sleep() //执行serialize()时,先会调用这个函数
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当尝试将对象调用为函数时触发

序列化的(构造payload)运行顺序

<?php
class A{public  $a=11;public function  __construct($b){  //2$this->a=$b;echo "A构造函数\n";}public function __wakeup(){echo "A苏醒函数\n";}public function  __destruct(){  echo "A析构函数first\n";        //3echo $this->a."aaa\n";echo "A析构函数second\n";       //5}
}
class B{public $x=1;public function  __construct($b){  //1$this->x=$b;echo "B构造函数\n";}public function  __toString(){     //4return "flag{a_b_c}";}public function  __destruct(){echo "B析构函数\n";    		   //6}
}
echo urlencode(serialize(new A(new B("Aa"))));
//O:1:"A":1:{s:1:"a";O:1:"B":1:{s:1:"x";s:2:"Aa";}}
//O%3A1%3A%22A%22%3A1%3A%7Bs%3A1%3A%22a%22%3BO%3A1%3A%22B%22%3A1%3A%7Bs%3A1%3A%22x%22%3Bs%3A2%3A%22Aa%22%3B%7D%7D
//先执行每个对象的构造函数,再执行析构函数
//结果:
//B构造函数
//A构造函数
//A析构函数first
//flag{a_b_c}aaa     (只要在构造payload的时候打印出了我们想要的东西,就是构造成功了)
//A析构函数second
//B析构函数
  • 运行顺序:

serialize()之后,依次执行:

__construct()
__toString()(如果被特定条件触发了)
__destruct()

析构方法在所有的代码被执行结束之后进行

反序列化的(实现payload)运行顺序

<?php
<?php
class A{public  $a=11;public function  __construct($b){$this->a=$b;echo "A构造函数\n";}public function __wakeup(){echo "A苏醒函数\n";             //1}public function  __destruct(){echo "A析构函数first\n";        //2echo $this->a."aaa\n";        echo "A析构函数second\n";       //4}
}
class B{public $x=1;public function  __construct($b){$this->x=$b;echo "B构造函数\n";}public function  __toString(){return "flag{a_b_c}";         //3}public function  __destruct(){echo "B析构函数\n";            //5}
}
unserialize($_GET[1]);
//echo urlencode(serialize(new A(new B("Aa"))));
//O:1:"A":1:{s:1:"a";O:1:"B":1:{s:1:"x";s:2:"Aa";}}
//1=O%3A1%3A%22A%22%3A1%3A%7Bs%3A1%3A%22a%22%3BO%3A1%3A%22B%22%3A1%3A%7Bs%3A1%3A%22x%22%3Bs%3A2%3A%22Aa%22%3B%7D%7D
//先执行wakeup函数,再执行触发了的toString函数,最后执行析构函数,就算用到了构造函数改变的值,也**不会主动去执行构造函数**
//结果:
//A苏醒函数
//A析构函数first
//flag{a_b_c}aaa
//A析构函数second
//B析构函数
  • 运行顺序:

unserialize()之后,依次执行:

__wakeup()
__toString()(如果被特定条件触发了)
__destruct()

析构方法在所有的代码被执行结束之后进行

绕过__wakeup()

  • 因为unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。__destruct()析构最后执行。所以有时执行wakeup的时候防止wakeup干坏事,我们就要绕过wakeup()函数:
PHP版本:
php5 < 5.6.25
php7 < 7.0.10

把类的属性值加1即可绕过wakeup:

O:5:"hello":1:{s:5:"test4";s:11:"hello,world";}

换成

O:5:"hello":2:{s:5:"test4";s:11:"hello,world";}

在这里插入图片描述

__tostring()

  • __toString 触发的条件比较多,也因为这个原因容易被忽略,常见的触发条件有下面几种
(1)echo ($obj) / print($obj) 打印时会触发(2)反序列化对象与字符串连接时(3)反序列化对象参与格式化字符串时(4)反序列化对象与字符串进行==比较时(PHP进行==比较的时候会转换参数类型)(5)反序列化对象参与格式化SQL语句,绑定参数时(6)反序列化对象在经过php字符串函数,如 strlen()addslashes()(7)in_array()方法中,第一个参数是反序列化对象,第二个参数的数组中有toString返回的字符串的时候toString会被调用(8)反序列化的对象作为 class_exists() 的参数的时候

由于是私有属性,他有自己特殊的格式会在前后加两个 %00 ,所以我们在传输过程中绝对不能忘掉. 反序列化字符串中存在 \x00字符,这个其实是类的私有属性反序列化后的格式,protected 属性也有自己的反序列化格式


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

相关文章

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

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

文章目录 前言一、等价类划分二、边界值三、错误推测法四、因果图法判定表驱动法设计步骤设计策略 前言 文章主要介绍常见测试用例的设计方法 提示&#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.…