jarvisoj phpinfo writeup及注入的变量详解

jarvisoj phpinfo writeup及注入的变量详解

这题目是关于php session反序列化的题目,参考了许多大神的writeup,但是注入点没有详细的讲解,因此自己想写一篇witeup

题目探索

首先打开题目页面直接获得源码:

// An highlighted block
<?php
//A webshell is wait for you
ini_set('session.serialize_handler', 'php');
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'));
}
?>

当new一个实例对象,会给属性mdzz赋值成phpinfo;当销毁一个实例对象,会执行eval函数,说明我们需要得到一个实例对象,并且我们可以控制mdzz的值,再让它销毁,从而执行eval函数。
传入参数phpinfo,得到对方的配置图,
jarvisoj phpinfo writeup及注入的变量详解_第1张图片
结合ini_set(‘session.serialize_handler’, ‘php’);配置中php_serialize的俩个值不同,php是当前脚本的配置,php_serialize是全局配置,是php.ini中设置的,可知该问题是php session反序列化问题。如果网站不同的php文件的写入Session的序列化方式与读取Session的反序列化方式不同,就可能导致漏洞的产生
各个配置的解释

配置 解释
session.upload_progress.enabled 是否启用上传进度报告(默认on),开启后会在上传文件时,将一个表示进度的数据结构传入$_SESSION
session.upload_progress.cleanup 是否在上传完成后及时删除进度数据(默认on,本题需要是off )
session.upload_progress.prefix 默认是upload_progress_
session.upload_progress.name 默认是PHP_SESSION_UPLOAD_PROGRESS
session.serialize_handler 对session进行序列化or反序列化的处理器:php、php_serialize(php>5.5.4)、php_binary
session.save_handler files表示session保存到会话文件中

各个处理器的序列化规则

配置 解释
php 对$_SESSION的每个元素对象单独调用serialize(),存储在文件。每个元素存储格式:键名+|+ serialize($_SESSION[‘key’])
php_serialize serialize($_SESSION)返回的字符串存储在会话文件中
php_binary 对$_SESSION的每个元素对象单独调用serialize(),存储在文件。存储规则:键名的长度对应的ASCII值+键名+serialize($_SESSION[‘key’])。

上传进度的数据结构,
进度数据将存储在$_SESSION[ini_get(“session.upload_progress.prefix”).$_POST[ini_get(“session.upload_progress.name”)]]
如图:upload_progress_是session.upload_progress.prefix的值,
laruence是$_POST[ini_get(“session.upload_progress.name”)]的值。

jarvisoj phpinfo writeup及注入的变量详解_第2张图片

注入实例的实现

由phpinfo()页面继续可知,session.upload_progress.enabled为On
jarvisoj phpinfo writeup及注入的变量详解_第3张图片且session.upload_progress.cleanup是off, 这两个配置决定了该上传进程的数据结构能保存在会话文件中。
自己写一个html文件实现 上传文件

<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>

抓包如图
jarvisoj phpinfo writeup及注入的变量详解_第4张图片
必须有上传一个参数,名是PHP_SESSION_UPLOAD_PROGRESS,值可以任意,

http报文中的filename的值对应$_SESSION[‘upload_progress_laruence’][‘files’][0][‘name’]
http报文中的name的值对应
$_SESSION[‘upload_progress_laruence’][‘files’][0][‘filed_name’]
这两处都可以实现攻击。

###具体过程的猜想:
上传文件时,记录上传进度数据到$_SESSION[‘upload_progress_laruence’],以php.ini中的session.serialize_handler指定的序列化方式保存在会话文件,
当对filename进行构造payload:
filname="|O:5:\“OowoO\”:1:{s:4:\“mdzz\”;s:20:\“var_dump($_SESSION);\”;}"

filname的字符串内容中的双引号必须加上\进行转义,否则会和filename=后的双引号闭合。
在这里插入图片描述
下图,是在本地搭建环境下,查看会话文件的保存内容
在这里插入图片描述
选中的字符串是filename的值,选中的字符串的后面的字符串在被php方式反序列化时,会被忽略。

但是当访问php文件时,且该文件带有ini_set(‘session.serialize_handler’, ‘php’);php文件将以该方式反序列化session文件中保存的数据,从而产生了OowoO类的实例,因为不是new产生的实例,不会执行__construct函数。php文件执行完后,销毁对象时,执行__destruct函数。
该php文件执行结束后,session又以php方式序列化保存$_SESSION。如图
在这里插入图片描述
竖线后的字符会被反序列化成为实例对象,竖线前的字符作为SESSION数组中OowoO实例的key,
构造payload的方法:filename=”|serialize(OowoW实例对象)” (注:字符串内容中的双引号要加上\)
payload注入点二
其实不一定要在filename处写payload,只要使上传进度的数据中field_name的值是payload,也是可以实现的,field_name对应http报文中的name。尝试对name写入payload
在这里插入图片描述
返回结果,表明执行了var_dump();
jarvisoj phpinfo writeup及注入的变量详解_第5张图片

最后,修改payload,使mdzz的值是print_r(scandir(dirname(FILE)));
jarvisoj phpinfo writeup及注入的变量详解_第6张图片
查出当前目录的文件
使mdzz=
print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"));
查出flag
jarvisoj phpinfo writeup及注入的变量详解_第7张图片

转载请注明出处

参考资料

https://www.cnblogs.com/sijidou/p/10455646.html
https://blog.csdn.net/wy_97/article/details/78430690

你可能感兴趣的:(ctf)