专栏名称: 狗厂
目录
相关文章推荐
51好读  ›  专栏  ›  狗厂

谈escapeshellarg绕过与参数注入漏洞

狗厂  · 掘金  ·  · 2018-05-03 10:53

正文

参数注入漏洞是指,在执行命令的时候,用户控制了命令中的某个参数,并通过一些危险的参数功能,达成攻击的目的。

0x01 从gitlist 0.6.0远程命令执行漏洞说起

我们从gitlist说起,gitlist是一款使用PHP开发的图形化git仓库查看工具。在其0.6.0版本中,存在一处命令参数注入问题,可以导致远程命令执行漏洞。

在用户对仓库中代码进行搜索的时候,gitlist将调用 git grep 命令:

<?php
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 是搜索的关键字, $branch 是搜索的分支。

如果用户输入的 $query 的值是 --open-files-in-pager=id; ,将可以执行 id 命令:

1.png

0x02 escapeshellarg为什么没有奏效?

导致这个漏洞的原因,有几点:

  1. 开发者对于 escapeshellarg 函数的误解,造成参数注入
  2. git grep 的参数 --open-files-in-pager 的值,将被直接执行

理论上,在经过 $query = escapeshellarg($query); 处理后, $query 将变成一个由单引号包裹的字符串。但不出漏洞的前提是,这个字符串应该出现在“参数值”的位置,而不是出现在参数选项(option)中。

我们可以试一下如下命令:

git grep -i --line-number -e '--open-files-in-pager=id;' master

2.png

如上图,我将 $query 放在了 -e 参数的值的位置,此时它就仅仅是一个字符串而已,并不会被当成参数 --open-files-in-pager

这应该作为本漏洞的最佳修复方法,也是git官方对pattern可能是用户输入的情况的一种解决方案(以下说明来自man-page):

-e
The next parameter is the pattern. This option has to be used for patterns starting with - and should be used in scripts passing user input to grep. Multiple patterns are combined by
or.

当然,gitlist的开发者用了另一种修复方案:

<?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;
    }

首先用 preg_replace - 开头的非法字符移除,然后将 $query 拼接在 -- 的后面。

在命令行解析器中, -- 的意思是,此后的部分不会再包含参数选项(option):

A -- signals the end of options and disables further option processing. Any arguments after the -- are treated as filenames and arguments. An argument of - is equivalent to --.

If arguments remain after option processing, and neither the -c nor the -s option has been supplied, the first argument is assumed to be the name of a file containing shell commands. If bash is invoked in this fashion, $0 is set to the name of the file, and the positional parameters are set to the remaining arguments. Bash reads and executes commands from this file, then exits. Bash's exit status is the exit status of the last command executed in the script. If no commands are executed, the exit status is 0. An attempt is first made to open the file in the current directory, and, if no file is found, then the shell searches the directories in PATH for the script.







请到「今天看啥」查看全文