先附上大神的原文链接:https://www.freebuf.com/articles/we/186298.html
故事源于一道CTF赛题:
这里的webshell过滤十分严格,采用不含f,l,a,g……并且绕过php内置函数。
注意:
PHP7前是不允许用($a)();这样的方法来执行动态函数的,但PHP7中增加了对此的支持。所以,我们可以通过(‘phpinfo‘)();来执行函数。(PHP7版本适用)执行:
echo urlencode(~‘phpinfo‘);//结果:%8F%97%8F%96%91%99%90
~为取反符号,对phpinfo取反是不可显的,故进行url编码。
pyload:
(~%8F%97%8F%96%91%99%90)();
PHP5版本无数字字母的webshell:
上述payload对于php5版本无效。
需要用到两个Linux Shell的知识:
1.shell下可以利用.来执行任意脚本
2.Linux文件名支持用glob通配符代替
.file执行文件是不需要具有x权限的,我们可以将文件传到/tmp的文件夹下,使用.来执行,使用通配符来代替文件名
如下是大佬的一举例(其中运用到了许多Linux的glob的绕过):
/tmp/phpXXXXXX就可以表示为/*/?????????或/???/?????????。
但我们尝试执行. /???/?????????,却得到如下错误:
这是因为,能够匹配上/???/?????????这个通配符的文件有很多,我们可以列出来:
可见,我们要执行的/tmp/phpcjggLC排在倒数第二位。然而,在执行第一个匹配上的文件(即/bin/run-parts)的时候就已经出现了错误,导致整个流程停止,根本不会执行到我们上传的文件。
其中,glob支持用[^x]的方法来构造“这个位置不是字符x”。那么,我们用这个姿势干掉/bin/run-parts:
排除了第4个字符是-的文件,同样我们可以排除包含.的文件:
现在就剩最后三个文件了。但我们要执行的文件仍然排在最后,但我发现这三个文件名中都不包含特殊字符,那么这个方法似乎行不通了。
继续阅读glob的帮助,我发现另一个有趣的用法:
就跟正则表达式类似,glob支持利用[0-9]来表示一个范围。
我们再来看看之前列出可能干扰我们的文件:
所有文件名都是小写,只有PHP生成的临时文件包含大写字母。那么答案就呼之欲出了,我们只要找到一个可以表示“大写字母”的glob通配符,就能精准找到我们要执行的文件。
翻开ascii码表,可见大写字母位于@与[之间:
那么,我们可以利用[@-[]来表示大写字母: