第二十二天php反序列化问题

这篇博客详细介绍了PHP的反序列化漏洞,包括序列化与反序列化的概念、PHP中的serialize()和unserialize()函数,以及魔法函数如__wakeup()和__destruct()在反序列化过程中的作用。通过实例展示了如何利用这些特性构造攻击,如控制对象变量、触发特定函数执行,从而引发代码执行等安全风险。此外,还分享了CTF挑战中的反序列化例题解析。
摘要由CSDN通过智能技术生成

序列化

百度百科上关于序列化的定义是,
将对象的状态信息转换为可以存储或传输的形式的过程。在序列化
期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对
象的状态,重新创建该对象。
简单的说,序列化就是把一个对象变成可以传输的字符串,可以以特定的格式在进程之间跨平台、安
全的进行通信。
PHP中的序列化与反序列化
PHP反序列化漏洞也叫PHP对象注入,是一个非常常见的漏洞,这种类型的漏洞虽然有些难以利用,但一
旦利用成功就会造成非常危险的后果。漏洞的形成的根本原因是程序没有对用户输入的反序列化字
符串进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、getshell等一系列不可控的
后果。反序列化漏洞并不是PHP特有,也存在于Java、Python等语言之中,但其原理基本相通。
PHP中的序列化与反序列化,基本都是围绕serialize()和unserialize()
两个函数展开的。在介绍这两个函数之前,我们来看一个简单的例子。
复习
class 类
obj 对象

对象(object)

对象就是具有一定功能和特征的事物.凡是能帮我们实现某种需求的事物的都是对象

a) 女朋友是对象.

b) 每一个学员都是讲师的教学对象.

类(class)

具有相同特征和功能的对象的抽象 就是类

很多个学生对象归纳为一个学生类.

很多个商品对象归纳为一个商品类.

对象和类之间的关系

对象参考类的结构,被创建出来.并且属性保存具体的数据.

它是具体的.

类是对所属对象的共有特性的描述, 可以说这是一个类型, 一个结构

它是抽象的

对象的抽象就是类

类的实体化(实例化)就是对象

对象和类的对比

马良         	 马良画的图       从画里走出来的事物

工程设计师      	设计图           由设计图造出来的事物

程序员         		类                对象
// 定义一个学生类 
class Student 
{
    
	// 成员属性(类中的变量) 
	public $name; 
	public $sex; 
	public $age;
    
	// 成员方法(类中的函数) 
	public function say()
	{
    
		echo '我爱写作业!<br>'; 
	} 
}

/*
a)成员属性
    i.必须要加修饰符来修饰   public 
    ii.成员属性的初始值可有可无
    iii.成员属性初始值的注意事项  
    iv.成员属性可以使用常量进行赋初始值

b)成员方法
    i.成员方法可以不加修饰符修饰   public 
    ii.成员方法中 参数可有可无 代码体可有可无 方法的返回值也是可有可无的
    iii.在成员方法(函数) 没有使用return手动返回一个值的话  它的默认返回值就是null
*/
// 根据类的结构,创建对象(术语:实例化对象) 
$stu1 = new Student;
/*
    1.new关键字不能省略  
    2.小括号可有可无
    3.对象的实例化 可以放在类声明之前   对象的实例化还可以放到类的内部
*/	

// 对象的成员访问
// 成员属性赋值 
$stu1 -> name = 'kpkp'; 
$stu1 -> sex = '男'; 
$stu1 -> age = 18; 

echo $stu1 -> name,'<br>'; 
$stu1 -> say();

/*
注意:
	1.如果属性名是固定的话  前面不能加$
	2.成员访问符的两侧可以有空白, 成员访问符的中间不能有空白
	3.成员属性和成员方法的位置不是绝对固定的 一般来说都是将成员属性放置在上面,成员方法放置在下面.
	4.在类中不能出现除了成员属性和成员方法之外的代码
*/


让对象表达自己($this)
php

class Student 
{
    
	public $name; 
	
	public function say() 
	{
    
		echo '我叫'.$this->name; 
	}
}

$stu1 = new Student; 

$stu1 -> name = '王建双'; 
$stu1 -> say(); // 我叫王建双
/*
	1 $this代表当前这个对象,谁调用当前这个方法,那么$this就代表(等于)哪个对象
	2.$this只能在类的内部使用  并且只能放置在成员方法中
	3.$this不仅能访问成员属性 还能在成员方法中调用成员方法

json 格式化字符串

*简单的例子
我们可以用json格式数据的编码与解码,来理解序列化与反序列化的过程。虽然json
数据与反序列化漏洞没有什么关系,但是这个例子会帮助我们理解。
测试代码如下

在这里插入图片描述
echo 不能输出数值
json 格式编码 就可以echo 输入了

在这里插入图片描述
我们定义一个数组,数组属于抽象的数据结构,
为了方便跨平台传输数据,可以将其进行json
编码。json格式的数据是以键值对的形式出现的。结果如下
*序列化Demo
序列化会将一个抽象的对象转换为字符串。
我们可以写一个Dm0来说明序列化的过程,首先创建一个类,代码如下
在这里插入图片描述
类名是Stu,该类中有四个变量(关于变量的性质,我们这里不讨论。接下来,我们可以将这个类实例化
,也就是创建一个对象,并给对象中变量赋值。代码如下

 <?php
class Student
{
   
    // 成员属性(类中的变量)
    public $name;
    public $sex;
    public $age;

    // 成员方法(类中的函数)
    public function say()
    {
   
        echo '我爱写作业!<br>';
    }
}
$a = new Student();
echo serialize($a);

在这里插入图片描述

了解反序列化,必先了解其魔法函数

  1. __sleep() //在对象被序列化之前运行
  2. __wakeup() //将在反序列化之后立即调用(当反序列化时变量个数与实际不符是会绕过)
  3. __construct() //当对象被创建时,会触发进行初始化
  4. __destruct() //对象被销毁时触发
  5. __toString()://当一个对象被当作字符串使用时 触发
  6. __call() //在对象上下文中调用不可访问的方法时触发
  7. __callStatic() //在静态上下文中调用不可访问的方法时触发
  8. __get() //获得一个类的成员变量时调用,用于从不可访问的属性读取数据
  9. __set() //用于将数据写入不可访问的属性
  10. __isset() //在不可访问的属性上调用isset()或empty()触发
  11. __unset() //在不可访问的属性上使用unset()时触发
  12. __toString() //把类当作字符串使用时触发
  13. __invoke() //当脚本尝试将对象调用为函数时触发

强调一下

构造函数 __construct
析构函数 __destruct
__call 调用类中不存在或者无法调用的非静态方法
__callStatic 调用类中不存在或者无法调用的静态方法
__invoke 将类所衍生的对象当作是函数进行调用
__get 当访问对象中一个不存在或者无法访问的属性时
__set 当设置对象中一个不存在或者无法设置的属性时
__wakeup 当使用Unserialize等反序列化函数生成对象时
__sleep 当使用serialize等序列化函数将对象转为字符串时 返回一个数组 该数组中绝对对那些程序属性进行序列化
__toString 当将类所衍生的对象当作字符串处理时

然后了解其属性

序列化对象:
private变量会被序列化为:\x00类名\x00变量名
protected变量会被序列化为: \x00*\x00变量名
public变量会被序列化为:变量名

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

序列化与反序列化
php中有两个函数serialize() 和unserialize()。

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"为字符串的名称,之后的类似。

unserialize()
与 serialize() 对应的,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);
?>

这里提醒一下,当使用 unserialize() 恢复对象时, 将调用 __wakeup() 成员函数。

反序列化漏洞

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

利用构造函数等

php中有一类特殊的方法叫“Magic function”,魔术方法 这里我们着重关注一下几个:

构造函数__construct():当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。
析构函数__destruct():当对象被销毁时会自动调用。
__wakeup() :如前所提,unserialize()时会自动调用。

测试如下:

<?php
class chybeta{
   
	var $test = '123';
	function __wakeup(){
   
		echo "__wakeup";
		echo "</br>";
	}
	function __construct(){
   
		echo "__construct"
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值