一、漏洞简介
1.1、了解序列化与反序列化
序列化
序列化是将变量转换为可保存或传输的字符串的过程。在PHP中序列化对应的函数为 serialize() 。
反序列化
反序列化就是在适当的时候把这个字符串再转化成原来的变量使用。在PHP中反序列化对应的函数为 unserialize() 。
1.2、PHP里的魔术方法
什么是魔术方法
魔术函数一般是以 __ 开头,通常会因为某些条件而触发不用我们手动调用。
在遇到反序列化漏洞的时候,碰见这几个魔术函数就要仔细研究了这些魔术方法都是常见的。
-
__construct()
-
__destruct()
-
__toString()
-
__sleep()
-
__wakeup()
PHP魔术函数
PHP魔术函数 | 描述 |
---|---|
__construct() | 当一个对象创建时被调用,构造函数 |
__destruct() | 在对象被销毁时执行该函数,析构函数 |
__toString() | 当一个对象被当成一个字符串使用 |
__sleep() | 在对象在被序列化之前运行 |
__wakeup() | 将在反序列化之后立即被调用 |
__call() | 在对象中调用一个不可访问方法时调用 |
__callStatic() | 用静态方式中调用一个不可访问方法时调用 |
__get() | 获得一个类的成员变量时调用 |
__set() | 设置一个类的成员变量时调用 |
__isset() | 当对不可访问属性调用isset()或empty()时调用 |
__unset() | 当对不可访问属性调用unset()时被调用 |
__invoke() | 调用函数的方式调用一个对象时的回应方法 |
__set_state() | 调用var_export()导出类时,此静态方法会被调用 |
__clone() | 当对象复制完成时调用 |
__autoload() | 尝试加载未定义的类 |
__debugInfo() | 打印所需调试信息序列化结构 |
二、漏洞利用
2.1、__destruct()
创建一个 destruct.php 文件,测试代码如下:
<?php
class Execute_Command{
public $test = "whoami";
function __destruct()
{
system($this -> test);
}
}
@$a= $_POST['id'];
$y= unserialize($a);
show_source(__FILE__);
?>
访问 destruct.php 文件路径。
这里有个类名为 Execute_Command 调用了 __destruct 魔术方法,该方法在对象被销毁时执行该函数。
对 Execute_Command 类实例化对象,然后进行序列化操作,并修改 Execute_Command 类中的 $cmd 字段的值。
将序列化后的字符串传递给 id 参数。
O:15:"Execute_Command":1:{s:4:"test";s:3:"dir";}
2.2、__toString
创建一个 toString.php 文件,测试代码如下:
<?php
class Execute_Command
{
public $cmd='whoami';
public function __toString()
{
return system($this->cmd);
}
}
@$obj = unserialize($_POST['id']);
echo $obj;
show_source(__FILE__);
?>
访问 toString.php 文件路径。
这里有个类名为 Execute_Command 调用了 __toString 魔术方法,该方法当一个对象被当成一个字符串使用。
对 Execute_Command 类实例化对象,然后进行序列化操作,并修改 Execute_Command 类中的 $cmd 字段的值。
将序列化后的字符串传递给 id 参数。
O:15:"Execute_Command":1:{s:3:"cmd";s:3:"dir";}
2.3、__wakeup()
创建一个 wakeup.php 文件,测试代码如下:
<?php
class Execute_Command{
public $test = "echo 'Hello World';";
function __wakeup()
{
eval($this -> test);
}
}
@$a= $_POST['id'];
$y= unserialize($a);
show_source(__FILE__);
?>
访问 wakeup.php 文件路径。
这里有个类名为 Execute_Command 调用了 __wakeup 魔术方法,该方法将在反序列化之后立即被调用。
对 Execute_Command 类实例化对象,然后进行序列化操作,并修改 Execute_Command 类中的 $cmd 字段的值。
将序列化后的字符串传递给 id 参数。