PHP反序列化漏洞总结

PHP

Posted by mr_king on October 11, 2020

PHP反序列化漏洞

[TOC]

漏洞简介

1.1什么是反序列化漏洞

利用程序已有的一些函数在参数中注入一些代码,达到代码执行的效果。

1.2漏洞危害

攻击者可以利用反序列化漏洞,通过构造恶意请求报文远程执行命令,危害较大。

漏洞原理

2.1 序列化与反序列化

在了解反序列化漏洞之前,必须要先了解什么序列化、反序列化以及它们各有什么用。

2.1.1 序列化

PHP语言为例子,在写程序尤其是写网站的时候,经常会构造,并且有时候会将实例化的类作为变量进行传输。序列化就是在此为了减少传输内容的大小孕育而生的一种压缩方法。我们知道一个PHP类都含有几个特定的元素: 类属性类常量类方法。每一个类至少都含有以上三个元素,而这三个元素也可以组成最基本的类。那么按照特定的格式将这三个元素表达出来就可以将一个完整的表示出来并传递。序列化就是将一个类压缩成一个字符串的方法。

<?php
class userInfo
{
    private $passwd = 'weak';
    protected $sex = 'male';
    public $name = 'ama666';

    public function modifyPasswd($passwd)
    {
        $this->passwd = $passwd;
    }

    public function getPasswd()
    {
        echo $this->$passwd;
    }
}

$ama666 = new userInfo();
$ama666->modifyPasswd('strong');
$data = serialize($ama666);
echo $data;
?>

得到的输出结果为

O:8:"userInfo":3:{s:16:"userInfopasswd";s:6:"strong";s:6:"*sex";s:4:"male";s:4:"name";s:6:"ama666";}

我们来逐一解读

  • 大括号外表示为“Object”对象名称长度为8是“userInfo”,这个对象有3个属性。
  • 大括号内表示的则是这些属性的具体信息以及它们的值。

根据属性的权限不同,在序列化中的表示方法也有所不同。可以看出在代码中三个属性的权限分别是privateprotectedpublic。这里简单说一下:

  • public权限就是正常的变量权限,一般声明的变量权限均为public
  • protected权限是私有权限,即只能在类内使用,子类可以继承这个变量
  • private权限也是私有权限,比protected权限更似有一些,只能在本类内使用,子类不能继承

总结来说一个类经过序列化之后存储在字符串的信息只有类名称和类内属性键值对,序列化字符串中没有将类方法一并序列化。这就引申出了本次讨论的主题,反序列化漏洞。

2.1.2 反序列化

反序列化与序列化相对应的,就是将含有类信息的序列化过的字符串“解压缩”还原成类。

0ccaKe.png

将字符串反序列化出来之后的类不包含任何类方法,那么这样一个类怎么起作用呢?

反序列化的类想要使用原先的类方法必须依托于,脱离了域的反序列的类是无法调用序列化之前的类方法的。比如我在上一段代码结尾加上如下代码

<?php
$new_ama666 = unserialize($data);
$new_ama666->getPasswd();
?>

2.2 PHP魔法函数

请参考PHP魔术函数总结

CTF中的反序列化

<?php
class SoFun{ 
    protected $file='index.php';
    function __destruct(){ 
        if(!empty($this->file)) {
            if(strchr($this-> file,"\\")===false &&  strchr($this->file, '\\')===false)
            show_source(dirname (__FILE__).'\\'.$this ->file);
        else{
            die('Wrong filename.');
        }
    }  
    function __wakeup()
    { 
        $this-> file='index.php'; 
    } 
    public function __toString()
    {
        return '' ;
    }
}     
    if (!isset($_GET['file'])) { 
        show_source('index.php'); 
    } 
    else { 
       $file=base64_decode( $_GET['file']); 
       echo unserialize($file ); 
    } 
?>   #<!--key in flag.php-->