1、相关背景介绍
当应用需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数。如PHP中的system、exec、shell_exec等,当用户可以控制命令执行函数中的参数时,将可以注入恶意系统命令到正常命令中,造成命令执行攻击。 这里还是主要以PHP为主介绍命令执行漏洞,Java等应用的细节待补充。
2、成因
脚本语言(如PHP)优点是简洁、方便,但也伴随着一些问题,如速度慢、无法接触系统底层,如果我们开发的应用(特别是企业级的一些应用)需要一些除去web的特殊功能时,就需要调用一些外部程序。
在PHP中可以调用外部程序的主要有以下函数:
systemexecshell_execpassthrupopen proc_popen
一些偏门函数就不说了,以上函数主要是在wbeshell里用的多,实际上在正常应用中差别不太大,用的最多的还是前三个。
应用在调用这些函数执行系统命令的时候,如果将用户的输入作为系统命令的参数拼接到命令行中,又没有过滤用户的输入的情况下,就会造成命令执行漏洞。
常见的一些成因:
1.一些商业应用需要执行命令,商业应用的一些核心代码可能封装在二进制文件中,再web应用中通过system函数来调用之:
system ( "/bin/program --arg $arg" ) ;
2.系统的漏洞造成命令注入:
不知各位看官是否还记得bash破壳漏洞,如果我们能够控制执行的bash的环境变量,就可以通过破壳漏洞来执行任意代码。
3.调用一些常用组件
很典型的就是Discuz中,可以选择使用ImageMagick这个常用的图片处理组件,对用户上传的图片进行处理(默认是GD库),而Discuz并没有很好控制用户的输入,造成命令执行,详见:DiscuzX系列命令执行分析公开(三连弹)。
另外JAVA中的命令执行漏洞(struts2/Elasticsearch Groovy等)很常见,亟待补充。
3、利用方法及危害
常见可控位置情况有下面几种:
system("$arg"); //可控点直接是待执行的程序system("/bin/prog $arg"); //可控点是传入程序的整个参数system("/bin/prog -p $arg"); //可控点是传入程序的某个参数的值(无引号包裹)system("/bin/prog --p=\"$arg\""); //可控点是传入程序的某个参数的值(有双引号包裹)system("/bin/prog --p='$arg'"); //可控点是传入程序的某个参数的值(有单引号包裹)
第一种情况
如果我们能直接控制$arg,那么就能执行执行任意命令了,没太多好说的。
第二种情况
我们能够控制的点是程序的整个参数,我们可以直接用&&或|等等,利用与、或、管道命令来执行其他命令(可以涉及到很多linux命令行技巧)。
还有一个偏门情况,当$arg被escapeshellcmd处理之后,我们不能越出这个外部程序的范围,我们可以看看这个程序自身是否有“执行外部命令”的参数或功能,比如linux下的sendmail命令自带读写文件功能,我们可以用来写webshell。
第三种情况
我们控制的点是一个参数,我们也同样可以利用与、或、管道来执行其他命令,情境与二无异。
第四种情况
这种情况压力大一点,有双引号包裹。如果引号没有被转义,我们可以先闭合引号,成为第三种情况后按照第三种情况来利用,如果引号被转义(addslashes),我们也不必着急。linux shell环境下双引号中间的变量也是可以被解析的。我们可以在双引号内利用反引号执行任意命令“ id
”
第五种情况
这是最难受的一种情况了,因为单引号内只是一个字符串,我们要先闭合单引号才可以执行命令。如:system(“/bin/prog –p='aaa' | id”)
危害自然不言而喻,执行命令可以读写文件、反弹shell、获得系统权限、内网渗透等。
4、案例
srun3000有多处因为命令执行造成的getshell:
深澜软件
可控点是参数:
宜搜某分站配置不当已被getshell
可控点是参数的值:
[再浅谈内网安全]--网神某带ids,waf网关设备完控0day又一枚
一个python绕过沙盒执行系统命令:
百度BAE系列2:系统命令执行,/etc/passwd及读写其它用户文件等
5、修复方案
1.能使用脚本解决的工作,不要调用其他程序处理。尽量少用执行命令的函数,并在disable_functions中禁用之。
2.对于可控点是程序参数的情况,使用escapeshellcmd函数进行过滤。
3.对于可控点是程序参数的值的情况,使用escapeshellarg函数进行过滤。
4.参数的值尽量使用引号包裹,并在拼接前调用addslashes进行转义。