escapeshellarg+escapeshellcmd
# escapeshellarg+escapeshellcmd
# escapeshellarg
版本:(PHP 4 >= 4.0.3, PHP 5, PHP 7)
escapeshellarg()
— 把字符串转码为可以在 shell 命令里使用的参数
功能:将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。shell 函数包含 exec(), system() 执行运算符(反引号)
定义如下:
string escapeshellarg ( string $arg )
没懂,实际例子如下:
经过 escapeshellarg 函数处理过的参数被拼凑成 shell 命令,并且被双引号包裹这样就会造成漏洞,这主要在于bash中双引号和单引号解析变量是有区别的
在解析单引号的时候 , 被单引号包裹的内容中如果有变量 , 这个变量名是不会被解析成值的,但是双引号不同 , bash 会将变量名解析成变量的值再使用
# escapeshellcmd
版本:(PHP 4, PHP 5, PHP 7)
escapeshellcmd()
— shell元字符转义
功能:对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符之前进行转义
反斜线\
会在以下字符之前插入: &#;`|*?~<>^()[]{}$, \x0A 和 \xFF;' 和**"仅在不配对儿**的时候被转义;在 Windows 平台上,所有这些字符以及 **%**和 ! 字符都会被空格代替
定义如下:
string escapeshellcmd ( string $command)
样例如下:
那么 escapeshellcmd 和 escapeshellarg 一起使用的时候会发生什么问题呢,我们继续看看,这两个函数都会对单引号进行处理,但还是有区别的,区别如下:
对于单个单引号, escapeshellarg 函数转义后,还会在左右各加一个单引号,但 escapeshellcmd 函数是直接加一个转义符,对于成对的单引号, escapeshellcmd 函数默认不转义,但 escapeshellarg 函数转义
# escapeshellarg()+escapeshellcmd()问题
escapeshellarg()和escapeshellcmd() 一起出现会有什么问题呢,我们举个简单例子如下:
这个过程如下:
传入的参数是
127.0.0.1' -v -d a=1
1由于
escapeshellarg
先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。所以处理之后的效果如下:'127.0.0.1'\'' -v -d a=1'
1经过
escapeshellcmd
针对第二步处理之后的参数中的\
以及a=1'
中的那个不配对儿的单引号进行处理转义之后的效果如下所示:'127.0.0.1'\\'' -v -d a=1\'
1最后执行的命令如下,由于中间的
\\
被解释为\
而不再是转义字符,所以后面的'
没有被转义,与再后面的'
配对儿成了一个空白连接符curl '127.0.0.1'\\'' -v -d a=1\'
1所以这个payload可以简化为
curl 127.0.0.1\ -v -d a=1'
,即向127.0.0.1\
发起请求,POST 数据为a=1'
tips:如果是先用 escapeshellcmd 函数过滤,再用的 escapeshellarg 函数过滤,则没有这个问题