shreyas-challa/CVE-2026-46394-haxcms-git-command-injection

GitHub: shreyas-challa/CVE-2026-46394-haxcms-git-command-injection

该项目是 HAXcms Git.php 命令注入漏洞(CVE-2026-46394)的 PoC 与完整分析报告,详述了 15 个未转义函数的根因、利用链及修复方案。

Stars: 0 | Forks: 0

# CVE-2026-46394 - HAXcms `Git.php` OS 命令注入 (CWE-78) | | | |---|---| | **CVE** | CVE-2026-46394 | | **组件** | HAXcms PHP 后端 - `system/backend/php/lib/Git.php` | | **漏洞** | OS 命令注入 (CWE-78) | | **严重程度** | 高 - CVSS 3.1 独立评分 **7.2** / 与路径遍历链接评分 **8.1** | | **状态** | 上游已修复。影响补丁之前的版本。 | | **项目** | [elmsln/HAXcms](https://github.com/elmsln/HAXcms) | | **报告者** | Shreyas Challa () | ## 摘要 HAXcms PHP 后端中的 `Git.php` 库通过拼接**未过滤的参数**来构建 shell 命令字符串,并将其直接传递给 `proc_open()`。在执行 shell 命令的 17 个函数中,只有**一个**(`commit()`)使用了 `escapeshellarg()`。其余的 **15** 个函数将调用者输入直接插入到命令字符串中。 任何包含 shell 元字符(`&`、`;`、`|`、`$()`、反引号)的值,只要到达这些函数之一,就会导致以 web 服务器用户身份执行**任意 OS 命令**。 唯一正确转义的函数是最清楚的证据,表明开发人员了解转义机制,只是在其他地方完全忽略了它。 ## 根本原因 每个易受攻击的函数都会流经 `run()` → `run_command()` → `proc_open()`: ``` // Git.php:408-411 - builds a raw command string public function run($command) { return $this->run_command(Git::get_bin() . " " . $command); } // Git.php:383 - executes it via the system shell $resource = proc_open($command, $descriptors, $pipes, $this->repo_path, $env); ``` 易受攻击的示例与唯一安全的函数对比: ``` // Git.php:574 - VULNERABLE (no escaping) public function create_branch($branch) { return $this->run("branch $branch"); } // Git.php:496 - SAFE (proves the author knew the pattern) public function commit($message = "") { return $this->run("commit -av -m " . escapeshellarg($message)); } ``` ### 所有受影响的函数 | 函数 | 行号 | Shell 命令 | 已转义? | |----------|------|---------------|----------| | `create_branch($branch)` | 574 | `branch $branch` | **否** | | `delete_branch($branch)` | 588 | `branch -d $branch` | **否** | | `checkout($branch)` | 663 | `checkout $branch` | **否** | | `merge($branch)` | 677 | `merge $branch --no-ff` | **否** | | `push($remote, $branch)` | 785 | `push $remote $branch $flags` | **否** | | `pull($remote, $branch)` | 799 | `pull $remote $branch` | **否** | | `log($format)` | 813 | `log --pretty=format:"$format"` | **否** | | `show($commit, $format)` | 830 | `show --pretty=format:"$format" $commit` | **否** | | `list_tags($pattern)` | 763 | `tag -l $pattern` | **否** | | `clone_to($target)` | 512 | `clone --local $repo $target` | **否** | | `clone_from($source)` | 527 | `clone --local $source $repo` | **否** | | `clone_remote($source)` | 543 | `clone $source $repo` | **否** | | `set_remote($dest, $url)` | 460 | `remote add $dest $url` | **否** | | `rm($files)` | 479 | `rm $files` | **否** | | `add_tag($tag, $msg)` | 749 | `tag -a $tag -m $msg` | `$tag`: **否**, `$msg`: 是 | | `commit($message)` | 496 | `commit -av -m $message` | **是** (唯一安全的函数) | ## 上下文中的漏洞利用 在发布的代码库中,这些函数使用来自服务器/站点配置而非直接来自请求体的值进行调用,因此漏洞利用是通过**链接**实现的: - **路径遍历 → 配置投毒 → RCE:**使用 `saveOutline` 路径遍历覆盖站点的 `site.json`,将元字符注入到 `metadata.site.git.branch` 中。下一次 `gitCommit()` 调用在 `HAXCMSSite.php:584` 处调用 `push('origin', $branch)`,从而执行 payload。 - 任何其他将 git 分支/远程设置写入清单的机制都会到达 `create_branch()`(`Operations.php:2762`)或 `set_remote()`(`HAXCMSSite.php:625`)。 ## 运行 PoC PoC 直接驱动真实的 `Git.php` 库:它启动一个临时的 git 仓库,使用包含 shell 命令分隔符的 payload 调用 `create_branch()`,并通过检查写入磁盘的证明文件来确认执行。它会在执行后自行清理。 ### 前置条件 - PHP CLI(7.x 或 8.x) - `PATH` 中的 `git` - HAXcms PHP 后端的副本 ``` git clone https://github.com/elmsln/HAXcms.git git clone https://github.com/shreyas-challa/CVE-2026-46394-haxcms-git-command-injection.git cd CVE-2026-46394-haxcms-git-command-injection ``` ### 运行 将 PoC 指向您 HAXcms 克隆中的 `Git.php`(通过环境变量或第一个参数);它还会自动发现放置在其旁边的 `haxcms-php/`: ``` # Option A - 环境变量 HAXCMS_PHP=../HAXcms/haxcms-php/system/backend/php/lib/Git.php php poc_git_cmdi.php # Option B - CLI 参数 php poc_git_cmdi.php ../HAXcms/haxcms-php/system/backend/php/lib/Git.php ``` 在 Unix(`;` 分隔符)和 Windows(`&` 分隔符)上均可运行;PoC 会自动为主机 OS 选择正确的 payload。 ### 示例输出 ``` ================================================================ HAXcms Git.php - OS Command Injection (CWE-78) ================================================================ STEP 3: Inject OS command via create_branch() Payload: test & echo COMMAND_INJECTION_PROOF > "...\PWNED.txt" STEP 4: Verify injected command executed FILE FOUND! Content: COMMAND_INJECTION_PROOF COMMAND INJECTION CONFIRMED. ``` ## 修复方案 对全部 15 个函数中的**每个**参数应用 `escapeshellarg()`: ``` // BEFORE public function create_branch($branch) { return $this->run("branch " . $branch); } // AFTER public function create_branch($branch) { return $this->run("branch " . escapeshellarg($branch)); } ``` 纵深防御 - 在值到达 git 层之前对其进行验证: ``` function validateBranchName($branch) { return preg_match('/^[a-zA-Z0-9._\/-]+$/', $branch) && strpos($branch, '..') === false; } ``` 更新至包含上游修复的最新 HAXcms 版本。 ## 负责任的披露 此问题已报告给 HAXcms 维护人员,并在发布前已修复。PoC 仅在补丁可用后发布。请仅针对您拥有或明确获得授权测试的系统使用它。 ## 法律 / 授权使用声明 本材料仅用于**防御性研究、教育和授权的安全测试**。未经明确许可对系统运行它可能是违法的。您需全权负责遵守所有适用法律,并在测试前获取授权。按“原样”提供,不附带任何担保(参见 `LICENSE`)。
标签:ffuf, OpenVAS, PHP, PoC, 命令注入, 暴力破解, 网络安全研究