任意命令执行
任意命令执行原因:
当应用需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数。如PHP中的system、exec、shell_exec等,当用户可以控制命令执行函数中的参数时,将可以注入恶意系统命令到正常命令中,造成命令执行攻击。
脚本语言(如PHP)优点是简洁、方便,但也伴随着一些问题,如速度慢、无法接触系统底层,如果我们开发的应用(特别是企业级的一些应用)需要一些除去WEB的特殊功能时,就需要调用一些外部程序。
在PHP中可以调用外部程序的常见函数:
system、exec、shell_exec、passthru、popen、proc_popen
应用在调用这些函数执行系统命令的时候,如果将用户的输入作为系统命令的参数拼接到命令行中,又没有过滤用户的输入的情况下,就会造成命令执行漏洞。
漏洞分类:
代码层过滤不严格:
一些商业应用需要执行命令,商业应用的一些核心代码可能封装在二进制文件中,在web应用中通过system函数来调用:system("/bin/program --arg $arg");
系统的漏洞造成命令执行:
bash破壳漏洞(CVE-2014-6271),如果我们控制执行的bash的环境变量,就可以通过破壳漏洞来执行任意代码。
调用第三方组件存在代码执行漏洞:
典型的就是WordPress中,可以选择使用ImageMagick这个常用的图片处理组件,对用户上传的图片进行处理(默认是ImageMagick库),造成命令执行。
JAVA中的命令执行漏洞(structs2、ElasticsearchGroovy等)
危害:
继承WEB服务程序的权限,执行系统命令
继承WEB服务程序的权限,读写文件
反弹shell
控制整个网站
甚至控制整个服务器
可以进一步的内网渗透
等等
漏洞利用:
<?php system($_GET['cmd']); ?>
http://127.0.0.1:8080/?cmd=id
· system("$arg"); 可控点直接是待执行的程序
如果我们能直接控制$arg,那么就能执行任意命令
· system("/bin/prog $arg"); 可控点是传入程序的整个参数
我们能够控制的点是程序的整个参数,我们可以直接用 && 或 | 等,利用与、或、管道命令来执行其他命令
当 $arg 被 escapeshellcmd 处理之后,我们不能越出这个外部程序的范围,我们可以看这个程序自身是否有“执行外部命令”的参数或功能,比如 LINUX 下的 sendmail 命令自带读写文件功能,可以用来写 webshell。
· system ("/bin/prog -p $arg"); 可控点是传入程序的某个参数的值(无引号包裹)
可控制的点是一个参数,同样可以使用 与、或、管道来执行其他的任意命令
· system("/bin/prog --p=\"$arg\""); 可控点是传入程序的某个参数的值(有双引号包裹)
因为有引号包裹,首先要分析引号是否被转义
如果没有被转义,先闭合引号,然后利用方法同上
如果被转义,双引号内的变量依然会被解析,利用反引号执行任意命令`id`
· system("/bin/prog --p='$arg'"); 可控点是传入程序的某个参数的值(有单引号包裹)
单引号内只是一个字符串,所以只能闭合单引号,才可利用
修复方案:
1.能使用脚本解决的工作,不要利用其他程序处理。尽量少用执行命令的函数,并在 disable_functions 中禁用
2.对于可控点是程序参数的情况,使用 escapeshellcmd 函数进行过滤 // escapeshellcmd() 除去字符串中的特殊符号
3.对于可控点是程序参数的值得情况,使用 escapeshellarg 函数进行过滤 // escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的
4.参数的值尽量使用引号包裹,并在拼接前调用 addslashes 函数进行转义
任意命令执行的前提:
代码中存在调用系统命令的函数
函数中存在我们可控的点
这个点没有过滤,或过滤不严格