漏洞简介
本漏洞是由escapeshellarg()
和escapeshellcmd()
两个函数对同一个需要过滤的shell命令字符串依次进行转义导致的参数逃逸问题,可以执行主命令的其他选修参数。
escapeshellarg()与escapeshellcmd()
escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入shell函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。shell 函数包含 exec(), system() 执行运算符 。
127.0.0.1' -d -v test
=>'127.0.0.1'\'' -v -d a=1'
escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。
反斜线(\)会在以下字符之前插入: \`|*?~<>^()[]{}$\, \x0A 和 \xFF。'
和"
仅在不配对儿的时候被转义。 在 Windows 平台上,所有这些字符以及%
和!
字符都会被空格代替。
127.0.0.1' -d -v test
=>127.0.0.1\' -d -v test
同时使用带来的漏洞
先使用escapeshellarg()
再使用escapeshellcmd()
就会导致参数逃逸。
例如:
$host = $_GET['host'];
echo $host."<br />";
$host = escapeshellarg($host);
echo $host."<br />";
$host = escapeshellcmd($host);
echo $host."<br />";
system('curl'.$host);
$host=127.0.0.1
127.0.0.1
'127.0.0.1'
'127.0.0.1'
$host=127.0.0.1'
127.0.0.1'
'127.0.0.1'\'''
'127.0.0.1'\\''\'
$host=127.0.0.1' -v -d a=1
127.0.0.1' -v -d a=1
'127.0.0.1'\'' -v -d a=1'
'127.0.0.1'\\'' -v -d a=1\'
我们可以注意到,Result3中最后结果会变成三个部分:
'127.0.0.1'
\\''
-v -d a=1\'
可以看到在2部分,原本用于转义'
的\
现在被另一个\
转义了,从而使得中间变为了\[空字符]
的形式,最后到system()
函数中的参数可以简化为curl 127.0.0.1\ -v -d a=1'
,即被解释为向127.0.0.1\
发起请求,POST参数为a=1'
,从而实现了选项参数的注入。