命令执行一般发生在远程,故被称为远程命令执行。
RCE漏洞,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统。
应用系统从设计上需要给用户提供指定的远程命令操作的接口。( 比如常见的路由器、防火墙、入侵检测等设备的web管理界面上)
一般会给用户提供一个ping操作的web界面,用户从web界面输入目标IP,提交后,后台会对该IP地址进行一次ping测试,并返回测试结果。
如果设计者在此输入界面的功能上没有做严格的安全控制,攻击者就可以通过此接口注入恶意的命令,让后台执行,从而控制整个后台服务器。
各类编程语言中,为方便程序处理,通常存在各种执行外部程序的函数,若调用函数执行命令未对输入过滤,进行注入恶意命令,就会达到攻击者的目的,造成危害。
前面讲到的函数用来执行命令,比如在PHP中,使用system、exec、shell_exec、passthru、popen
等函数可以执行系统命令。攻击者控制这些函数中的参数时,可将恶意的系统命令拼接到正常命令中,造成命令执行攻击,就是命令执行漏洞。
举例:
PHP中的system() 函数
$dir = $_GET['d'];
system("echo ".$dir);
?>
这一小段代码正常的功能是调用操作系统的 echo 程序,将 d 参数接收到的字符串输出,然后通过 system() 函数将echo 程序执行的结果返回在网页中。
此时如果在 d 参数后面加上 “&& whoami”,url转义后为 “%26%26 whoami”,系统就会执行echo 程序和我们后面加上的 whoami 程序。
echo system("ping -n 2" . $_GET['ip']);
?>
这是一段服务端处理ping的代码,程序获取GET参数IP,然后拼接到system() 函数中,利用 system() 函数执行ping 功能,此处没有对参数 IP 做过滤和检测。
尽量不要使用命令执行函数。
客户端提交的变量在进入执行命令函数前要做好过滤和检测。
使用动态函数之前,确保使用的函数是指定的函数之一。
对PHP语言来说,最好不使用不能完全控制的危险函数。
转义字符可以去掉特殊字符的特殊意义。
Windows的转义字符为“^”,使用后,可以看到原本存在特殊意义的“&”被取消意义。
Linux的转义字符为“\”,使用后,原本存在特殊意义的“&”被取消意义。
Windows系统支持的管道符
“|”:直接执行后面的语句,如 ping 127.0.0.1|whoami ,只执行whoami程序。
“||”:如果前面语句执行错误,则执行后面的语句,前面的语句只能为假。如 ping 2 || whoami 。
“&”:如果前面的语句为假则直接执行后面的语句,前面的语句可真可假。如 ping 127.0.0.1&whoami 。
“&&”:如果前面的语句为假则直接出错,也不执行后面的语句,前面的语句只能为真。如 ping 127.0.0.1&&whoami 。
Linux系统支持的管道符
“;”:执行完前面的语句再执行后面的。如 ping 127.0.0.1;whoami 。
“|”:显示后面语句的执行结果。如 ping 127.0.0.1|whoami 。
“||”:当前面的语句执行错误时,执行后面的语句,如 ping 127.0.0.1||whoami 。
“&”:如果前面的语句为假则直接执行后面的语句,前面的语句可真可假。如ping 127.0.0.1&whoami 。
“&&”:如果前面的语句为假则直接出错,也不执行后面的,前面的语句只能为真。如ping 127.0.0.1&&whoami 。
与代码中的注释一样,比如c语言中的“//”注释。合理利用在命令执行中,能够使命令后面的其他字符成为注释内容,可以降低程序执行的错误。
Windows的注释符号为“::”
Linux的注释符号为“#”
命令执行的绕过
在一些代码审计中经常是禁止出现空格的,输入的空格会被过滤为空。
比如一个参数“echo web”,中间是有一个空格的,被过滤为空的话,就变成了“echoweb”。
在命令中有间隔作用的不只有空格。可以用其他字符代替
< 、<>、%20(space)、%09(tab)、$IFS$9、 ${IFS}、$IFS、$IFS$1
IFS(Internal Field Separator)
是Linux存在的环境变量,是内部字段分隔符。
如果单纯的“ I F S a a a ” , 会 被 直 接 解 析 为 I F S a a a 是 整 个 变 量 名 , 而 在 L i n u x 中 “ IFSaaa”,会被直接解析为 IFSaaa 是整个变量名, 而在Linux中“ IFSaaa”,会被直接解析为IFSaaa是整个变量名,而在Linux中“IFSaaa” 变量是不存在的。所以需要间隔符来避免,通常用“$9”。
“ 9 ” 表 示 当 前 系 统 s h e l l 进 程 的 第 九 个 参 数 , 通 常 是 一 个 空 字 符 , 所 以 前 面 的 “ 9”表示当前系统 shell 进程的第九个参数,通常是一个空字符,所以前面的 “ 9”表示当前系统shell进程的第九个参数,通常是一个空字符,所以前面的“IFSaaa”
可以改为 “$IFS$9aaa” 。同理也可以加一个{}固定变量名。
1、拼接绕过
在Linux中:
a=c;b=at;c=he;d=llo;$a$b ${c}${d}
这里,把其他的字符赋值给一个变量,那么最终 a a ab是cat ,${c}{d}为hello 。
2、单、双引号绕过
如: cat flag
绕过后:ca’'t flag 或 cat"" flag
4、反斜线
如:cat flag
绕过后:ca\t fl\ag
5、通配符绕过
在通配符中,“?”代表任意一个字符串,“*”代表任意个字符串。(区分任意一个和任意个)
Windows下: type fla*
Linux下:cat /tm?/fl*