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, 命令注入, 暴力破解, 网络安全研究