php反序列化原理常见的魔术方法

序列化是什么?

要想了解反序列化,就先要知道序列化是什么。下面是是一串序列化数组:

a:2:{s:4:"name";s:6:"cike_y";s:3:"age";i:18;}
  • a表示array(数组),2表示这个数组有两个元素。
  • 第一个元素s代表字符串,长度为4,键值是name,然后分号分隔;接下来name的值为cike_y,它的长度为六,也是字符串。
  • 第二个元素age键名,类型为字符串,键名的值是18,i代表的是整数。

构造序列化函数使用serialize函数,将一个可读的字符串打包成难理解的序列化数组

<?php

// 构造数组
$data = array(
    "name" => "cike_y",
    "age" => 18
);

// 序列化数组
$serializedData = serialize($data);

// 输出序列化字符串
echo $serializedData;

image.png

反序列化

将序列化数组进行逆转过来,就是反序列化,简而言之就是一串很难理解的字符串反序列化为很直观的形式,如前面的示例:

<?php
$serialize_array = 'a:2:{s:4:"name";s:6:"cike_y";s:3:"age";i:18;}';
var_dump (unserialize($serialize_array)); //unserialize函数为反序列化函数

访问控制

php对属性或者方法控制,是通过在前面添加关键字来进行实现的。

  • public (公有):公有的类成员可以在任何地方被访问。
  • protected (受保护): 受保护的类成员则可以被其自身以及其子类和父类访问。
  • private (私有) :私有的类成员则只能被其定义所在的类访问。

演示代码:

<?php
class Myclass {
    public $name1;
    protected $name2;
    private $age;
    
    function __construct($name1,$name2,$age) {
        $this->name1 = $name1;
        $this->name2 = $name2;
        $this->age = $age;
    }
}

// 序列化
$a = new Myclass();
$a->name1 = "cike";
#$a->name2 = "_y";
#$a->age = "18";
$str = serialize($a);
$str2 = urlencode($str);
echo "序列化的内容:<br>";
echo "没有url编码:".$str."<br>";
echo "有url编码的:".$str2."<br>";

// 反序列化
$a2 = unserialize($str);
echo "<br>反序列化的内容:<br>";
echo var_dump($a2)."<br>";
print_r($a2);

?>
    

运行php文件后发现只有cike进行输出了,其他的值为空,可能觉得认为是注释掉了,所以才没有进行回显,但并不是
image.png
public变量是公共变量,可以使用属性赋值,而其他成员却是不能直接使用属性赋值的方法,这时候取消剩下两个不同成员的属性赋值注释:

<?php
class Myclass {
    public $name1;
    protected $name2;
    private $age;
    
    function __construct($name1,$name2,$age) {
        $this->name1 = $name1;
        $this->name2 = $name2;
        $this->age = $age;
    }
}

// 序列化
#$a = new Myclass("cike", "_y" , 18);
$a = new Myclass();
$a->name1 = "cike";
$a->name2 = "_y";
$a->age = "18";
$str = serialize($a);
$str2 = urlencode($str);
echo "序列化的内容:<br>";
echo "没有url编码:".$str."<br>";
echo "有url编码的:".$str2."<br>";

// 反序列化
$a2 = unserialize($str);
echo "<br>反序列化的内容:<br>";
echo var_dump($a2)."<br>";
print_r($a2);

?>
    

可以看见出现了报错,中文意思为以下

致命错误:无法访问 test.php在第18行中的受保护属性myclass :: $ name2

说明了不同的成员变量的访问性质也不同
image.png

不同成员变量的编码

<?php
class Myclass {
    public $name1;
    protected $name2;
    private $age;
    
    function __construct($name1,$name2,$age) {
        $this->name1 = $name1;
        $this->name2 = $name2;
        $this->age = $age;
    }
}

// 序列化
$a = new Myclass("cike", "_y" , 18);

$str = serialize($a);
$str2 = urlencode($str);
echo "序列化的内容:<br>";
echo "没有url编码:".$str."<br>";
echo "有url编码的:".$str2."<br>";

// 反序列化
$a2 = unserialize($str);
echo "<br>反序列化的内容:<br>";
echo var_dump($a2)."<br>";
print_r($a2);

?>
    

可以看见 protected成员和private成员如果是直接输出会略过特殊的字符串,因为不会显示%00。而public变量的成员则没有特殊字符

序列化的内容:
没有url编码:O:7:"Myclass":3:{s:5:"name1";s:4:"cike";s:8:"*name2";s:2:"_y";s:12:"Myclassage";i:18;}
有url编码的:O%3A7%3A%22Myclass%22%3A3%3A%7Bs%3A5%3A%22name1%22%3Bs%3A4%3A%22cike%22%3Bs%3A8%3A%22%00%2A%00name2%22%3Bs%3A2%3A%22_y%22%3Bs%3A12%3A%22%00Myclass%00age%22%3Bi%3A18%3B%7D

反序列化的内容:
object(Myclass)#2 (3) { ["name1"]=> string(4) "cike" ["name2":protected]=> string(2) "_y" ["age":"Myclass":private]=> int(18) }
Myclass Object ( [name1] => cike [name2:protected] => _y [age:Myclass:private] => 18 )

O:7:“Myclass”:3 // O表示对象,类名长度为7,类名为Myclass,有三个成员,大括号里面是三个成员变量的信息

  • public成员变量的名字直接写

  • protected成员变量的名字前需要加%00类名*%00

  • private成员变量等待名字前需要加%00类名%00

    其中%00为一个字符

常见的绕过

十六进制绕过

这是一个简单的例子:

<?php
class test{
    public $username;
    public function __construct(){
        $this->username = 'admin';
    }
}
function waf($data){
    if(stristr($data, 'username')!==False){
        echo("hcaker!");
    }
    else{
        echo "flag{@_@}";
    }
}


$a = $_GET['source'];
$a = waf($a);
unserialize($a);

可以看见如果想要输入username,就会被过滤掉
image.png
当表示字符串的s变成大写时,会被当成十六进制进行解析

O:4:"test":1:{s:8:"username";s:5:"admin";}
//改成以下
O:4:"test":1:{S:8:"\\75sername";s:5:"admin";}
//u的十六进制就是\\75

引用绕过

比如题目对 c o n r r e c t 变量进行 b a s e 64 解密什么的,必须要 conrrect变量进行base64解密什么的,必须要 conrrect变量进行base64解密什么的,必须要input变量等于$correct 才能获得flag

<?php
class BUU {
   public $correct = "";
   public $input = "";
}

$a = new BUU();

/*主要的绕过方式*/
$a->correct = ""; //先让correct的值为空
$a->input = &$a->correct; 
#在 PHP 中,使用 & 符号表示引用赋值,意味着两个变量将指向同一个数据空间,从而使他们两个相等
echo serialize($a);

?>

具体可以参考我之前的刷题文章

https://blog.csdn.net/weixin_53912233/article/details/128105583

__wakeup绕过

绕过的版本范围:

  • PHP5 < 5.6.25
  • PHP7 < 7.0.10

具体可以参考我之前这篇文章

https://blog.csdn.net/weixin_53912233/article/details/128069937

php反序列化常见的魔术方法

__invoke()方法

实例化该方法的类后,再以函数的方式调用类,就可以触发__invoke方法

<?php
class Myclass
{
    public function __invoke()
    {
        echo '__invoke方法调用成功';
    }

}


$a = new Myclass();
$a(); //实例化类后,以函数的形式进行调用,可以触发__invoke方法
;?>

可以发现当$a()执行之后就会成功调用invoke方法
image.png

__wakeup()方法

该方法在反序列化对象的时候会进行调用,在php中unserialize函数为反序列化函数

<?php
class Myclass{

    public function __wakeup(){
        echo "我已经被反序列化了,可以执行苏醒函数了";
	}
}
$obj = new Myclass();
$serialize_obj = serialize($obj);
unserialize($serialize_obj); //反序列化对象

当unserialize函数执行完毕之后,可以看见成功调用了__weakeup()魔术方法
image.png

__sleep()方法

当该对象执行serialize函数的时候,进行序列化的时候会进行调用,如下

<?php
class Myclass{

    public function __sleep(){
        echo "我已经被序列化了,可以执行睡觉函数了";
	}
}
$obj = new Myclass();
serialize($obj); //序列化对象

可以看见执行serialize函数的时候,会调用__sleep()方法
image.png

__construct()方法

构造方法,实例化对象的时候自动调用的方法,如下:

<?php
class MyClass {
	public function __construct() {
		echo "对象创建成功!";
	}
}

$obj = new MyClass(); //实例化MyClass对象

可以看见实例化的时候,会调用__construct()魔术方法。
image.png

__destruct()方法

销毁函数,当脚本执行结束的时候就会运行该方法,如下:

<?php

class Myclass {

    function __construct() {
		echo "aa ";
	}
    function __destruct() {


        print "bb";
    }
}

$obj = new Myclass();


创建 $obj 对象时,调用 __construct() 方法,输出 aa。执行完上述之后,就会调用销毁函数,最后输出bb
image.png

__toString()方法

当该方法的对象时被当作字符串输出,会返回__toString方法的字符串。比如:

<?php

class Myclass {

    function __toString() {
		return "执行toString魔术方法";
	}
}

$obj = new Myclass();
echo $obj;

可以看见输出对象当作字符串的时候,就会成功调用__toString魔术方法,并且返回它的字符串信息
image.png

__get()方法

该方法当访问一个对象的不可访问属性时被调用,会自动调用,如下

<?php
  class Myclass{
  public function __get($name){
    echo $name;
  }
}
  $obj = new Myclass();
$obj->hello;

可以看见调用了一个不存在的hello,最后触发了__get()方法,输出了hello
image.png

__set()方法

__set($name, v a l u e ) 方法,当给对象的不可访问属性赋值时被调用。其中 value)方法,当给对象的不可访问属性赋值时被调用。其中 value)方法,当给对象的不可访问属性赋值时被调用。其中name指的是键名,$value指的是值。

<?php
class Myclass{
    public function __set($name,$value){
        echo $name."-----".$value;
	}
}
$obj = new Myclass();
$obj->me = "hello";

最后可以看见成功调用__set()方法
image.png

__isset()方法

该方法,当用isset()或empty()判断该当前对象不可见属性的时候,就会调用

<?php
class Myclass{
	
	//获取不可见属性时,被调到触发
    public function __isset($a){
        echo $a."<br>";
	}
}
$obj = new Myclass();
isset($obj->a);
empty($obj->b);

可以看见当·访问量不可见的a和b属性的时候就成功输出了a和b。
image.png

__unset()方法

该魔术方法同__isset()方法差不多。当使用unset()判断一个该对象不可见属性的时候就会调用__isset()方法

<?php
class Myclass{
	
	//获取不可见属性时,被调到触发
    public function __unset($a){
        echo $a."<br>";
	}
}
$obj = new Myclass();
unset($obj->a);

可以看见成功调用了_unset()方法
image.png

__call()方法

__call()该方法在调用的方法不存在时会自动调用,这个方法接受两个参数。如下:

<?php
class MyClass
{
	function __call($class_name, $args)
    {
		echo "__call方法调用成功<br>";
        var_dump($class_name,$args);
	}
}
    

$a=new MyClass();
$a->test("test1","test2");

test()方法是不存在的,访问php文件,可以看见成功调用__call()方法。
test是方法名,test1和test2是test方法的参数。
image.png

__callStatic()方法

  1. 当该方法的对象要调用的静态方法不存在或者权限不足时候会调用该方法
  2. 接受的参数为数组形式

如下例子:

<?php
class Myclass
{
    private static function name()  
    {
        echo 'hhhhhhhhh';
    }
 
    public function __callStatic($function_name, $arg)
    {
        echo  "__callStatic方法调用成功";
		var_dump($function_name,$arg);
		die;
    
    }
}

$a = new Myclass();
$a::test("参数1","参数2");
//或 Myclass::test("参数1","参数2"); 
?>

可以发现当该对象调用私有的静态name方法时,成功调用了__callStatic()方法,并且执行了不存在的方法
image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/398535.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Maxwell - 增量数据同步工具

前言 今天来学习一个新的大数据小工具 Maxwell &#xff0c;它和 Sqoop 很像。Sqoop主要用于在 Hadoop &#xff08;比如 HDFS、Hive、HBase 等&#xff09;和关系型数据库之间进行数据的批量导入和导出&#xff0c;而 Maxwell 则主要用于监控数据库的变化&#xff08;通过监控…

详解AT24CXX驱动开发(linux platform tree - i2c应用)

目录 概述 1 认识AT24Cxx 1.1 AT24CXX的特性 1.2 AT24CXX描述 1.2.1 引脚 1.2.2 容量描述 1.2.3 设备地址 1.3 操作时序 1.3.1 写单个字节时序 1.3.2 写page字节时序 1.3.3 读取当前数据时序 1.3.4 随机读取数据 1.3.5 连续读取多个数据 2 驱动开发 2.1 硬件接口…

爬虫案例|采集某东商品评论信息|API数据接口 python实例

前言&#xff1a; 平常大家都有网上购物的习惯&#xff0c;在商品下面卖的好的产品基本都会有评论&#xff0c;当然也不排除有刷评论的情况&#xff0c;因为评论会影响我们的购物决策。今天主要分享用pythonre正则表达式获取京东商品评论。可以直接采用API接口接入形式大规模采…

【洛谷 P8780】[蓝桥杯 2022 省 B] 刷题统计 题解(贪心算法+模拟+四则运算)

[蓝桥杯 2022 省 B] 刷题统计 题目描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a a a 道题目&#xff0c;周六和周日每天做 b b b 道题目。请你帮小明计算&#xff0c;按照计划他将在第几天实现做题数大于等于 n n n 题? 输入格式 输入一…

python使用openpyxl添加图片到excel文件中

文章目录 openpyxl添加图片方法示例程序 openpyxl添加图片方法 图片只能保存在某个sheet页面中&#xff0c;因此首先打开sheet页面&#xff1a; openpyxl.load_workbook("测试excel.xlsx")然后创建一个图片&#xff1a; input_sheet excel_workbook["Sheet1…

java—泛型编程

文章目录 什么是泛型为什么需要泛型 泛型的使用泛型的上界 泛型方法的使用引出泛型方法 泛型是如何编译的擦除机制 什么是泛型 首先什么是泛型呢&#xff1f;从字面上我们可以理解为广泛的类型&#xff0c;有一定c基础的程序猿们应该了解&#xff0c;java中的泛型其实就是c的模…

小米14 ULTRA:重新定义手机摄影的新篇章

引言 随着科技的飞速发展&#xff0c;智能手机已经不仅仅是一个通讯工具&#xff0c;它更是我们生活中的一位全能伙伴。作为科技领域的佼佼者&#xff0c;小米公司再次引领潮流&#xff0c;推出了全新旗舰手机——小米14 ULTRA。这款手机不仅在性能上进行了全面升级&am…

UE5 C++ 静态加载资源和类

一.上篇文章创建组件并绑定之后 在Actor中加载初始化了组件&#xff0c;现在在组件中赋值。使用static ConstructorHelpers::FObjectFinder<T>TempName(TEXT("Copy Reference"))&#xff1b;再用TempName.Object //静态加载资源static ConstructorHelpers::FOb…

Java HashMap源码剖析

字面上看&#xff0c;HashMap由Hash和Map两个单词组成&#xff0c;Map表示映射关系&#xff0c;是一个接口&#xff0c;实现Map接口有多种方式&#xff0c;HashMap实现的方式利用了Hash。本文先分析Map接口&#xff0c;接着分析HashMap实现原理&#xff0c;最后总结分析HashMap…

【云原生系列之kubernetes】--Ingress使用

service的缺点&#xff1a; 不支持基于URL等机制对HTTP/HTTPS协议进行高级路由、超时、重试、基于流量的灰度等高级流量治理机制难以将多个service流量统一管理 1.1ingress的概念 ingress是k8s中的一个对象&#xff0c;作用是如何将请求转发到service的规则ingress controlle…

STM32-启用蜂鸣器

目录 1 、电路构成及原理图 2、编写实现代码 main.c beep.c beep.h 3、代码讲解 4、 烧录到开发板调试、验证代码 5、检验效果 本人使用的是朗峰 STM32F103 系列开发板&#xff0c;此笔记基于这款开发板记录。 1 、电路构成及原理图 首先&#xff0c;通过朗峰 F1 开…

14. rk3588自带的RKNNLite检测yolo模型(python)

首先将文件夹~/rknpu2/runtime/RK3588/Linux/librknn_api/aarch64/下的文件librknnrt.so复制到文件夹/usr/lib/下&#xff08;该文件夹下原有的文件librknnrt.so是用来测试resnet50模型的&#xff0c;所以要替换成yolo模型的librknnrt.so&#xff09;&#xff0c;如下图所示&am…

相机图像质量研究(36)常见问题总结:编解码对成像的影响--块效应

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

uniapp开发小程序项目

下载hbuilder 官网入口 下载地址 解压安装包 HBuilderX&#xff0c;Windows为zip包&#xff0c;解压后才能使用。 首先&#xff0c;选中下载的zip包&#xff0c;点击右键菜单&#xff0c;点击解压到当前文件夹进入解压后的文件夹&#xff0c;找到HBuilderX.exe&#xff0c;…

Leetcoder Day16| 二叉树 part05

语言&#xff1a;Java/C 513.找树左下角的值 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7 本题需要满足两…

Flink/flinksql 语法 窗口与join 一文全 相关概念api汇总总结,底层process算子总结,与数据延迟处理,超时场景解决方案

Flink 窗口概念与join汇总总结 1 SQL语法中窗口语法相关&#xff08;仅仅是flinksql中 窗口的语法&#xff09;1.1 sql窗口1.2 window topN 2 java/SQL join语法与介绍2.1 有界join2.1.1 Window Join2.1.2 Interval Join2.1.3 Temporary Join2.1.4 LoopUp Join2.2 无界join2.2.…

MyBatis学习总结

MyBatis分页如何实现 分页分为 逻辑分页&#xff1a;查询出所有的数据缓存到内存里面&#xff0c;在从内存中筛选出需要的数据进行分页 物理分页&#xff1a;直接用数据库语法进行分页limit mybatis提供四种方法分页&#xff1a; 直接在sql语句中分页&#xff0c;传递分页参数…

js设计模式:原型模式

作用: 使用js特有的原型链机制,可以通过Object.create方法创建新对象,将一个对象作为另外一个对象的原型 也可以通过修改原型链上的属性,影响新对象的行为 可以更方便的创建一些对象 示例: let obj {getName: function(){return this.name},getAge:function(){return this…

【Flutter】底部导航BottomNavigationBar的使用

常用基本属性 属性名含义是否必须items底部导航栏的子项List是currentIndex当前显示索引否onTap底部导航栏的点击事件&#xff0c; Function(int)否type底部导航栏类型&#xff0c;定义 [BottomNavigationBar] 的布局和行为否selectedItemColor选中项图标和label的颜色否unsel…

[office] excel图表怎么发挥IF函数的威力 #微信#媒体

excel图表怎么发挥IF函数的威力 IF函数应该是最常用的Excel函数之一了&#xff0c;在公式中经常能够看到她的“身影”。IF函数的基本使用如图1所示。 图1 IF函数之美 IF函数是一个逻辑函数&#xff0c;通过判断提供相应操作&#xff0c;让Excel更具智能。 然而&#xff0c;…