这道题的限制:
-
webshell长度不超过35位
-
除了不包含字母数字,还不能包含
$
和_
难点呼之欲出了,以前的
PHP7前是不允许用($a)();
这样的方法来执行动态函数的,但PHP7中增加了对此的支持。所以,我们可以通过('phpinfo')();
来执行函数,第一个括号中可以是任意PHP表达式。 所有方法,都用到了PHP中的变量,需要对变量进行变形、异或、取反等操作,最后动态执行函数。但现在,因为$
不能使用了,所以我们无法构造PHP中的变量。
我们尝试对('phpinfo')();进行取反操作后得到
(~%8F%97%8F%96%91%99%90)();
在php5中不能再这样做尝试其他方法:POST文件
现在我们尝试向这个程序POST一个文件,让它生成一个临时文件,但是这个临时文件会被很快删掉,而且临时文件名不知道;
先写一个上传:
因为反引号不属于“字母”、“数字”,所以我们可以执行系统命令,但问题来了:如何利用无字母、数字、$
的系统命令来getshell?
问题又回到了原点:无字母、数字、$
,在shell中仍然是一个难题。
此时有两个有趣的Linux shell知识点:
-
shell下可以利用
.
来执行任意脚本 -
Linux文件名支持用glob通配符代替
第一点.
或者叫period,它的作用和source一样,就是用当前的shell执行一个文件中的命令。比如,当前运行的shell是bash,则. file
的意思就是用bash执行file文件中的命令。
用. file
执行文件,是不需要file有x权限的。那么,如果目标服务器上有一个我们可控的文件,那不就可以利用.
来执行它了吗?
这个文件也很好得到,我们可以发送一个上传文件的POST包,此时PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX
,文件名最后6个字符是随机的大小写字母。
第二个难题接踵而至,执行. /tmp/phpXXXXXX
,也是有字母的。此时就可以用到Linux下的glob通配符:
-
*
可以代替0个及以上任意字符 -
?
可以代表1个任意字符
那么,/tmp/phpXXXXXX
就可以表示为/*/?????????
或/???/?????????
。
但是这样会把系统所有的匹配文件都会匹配出来,系统所有文件名都是小写,只有PHP生成的临时文件包含大写字母。那么答案就呼之欲出了,我们只要找到一个可以表示“大写字母”的glob通配符,就能精准找到我们要执行的文件。于是:
glob支持用
[^x]
的方法来构造“这个位置不是字符x”。glob支持利用
[0-9]
来表示一个范围。在ASCII码中:大写字母位于
@
与[
之间
所以我们构建的code值是:
?><?=`
. /???/????????[@-[];`?>
开始:
我们首先要抓一个文件上传的包的一部分:
再抓php包,然后更改POST、code以及包结构;
结果: 成功执行了
#!/bin/bash
id