
PoC und Beschreibung für CVE-2026-46394: OS command injection in HAXcms Git.php (CWE-78). Nur für autorisierte Sicherheitsforschung.
Git.php OS-Befehlseinschleusung (CWE-78)Proof-of-Concept nur für autorisierte Sicherheitstests und Forschung. Die hier beschriebene Schwachstelle ist in der neuesten Version von HAXcms behoben. Dieser PoC wird veröffentlicht, damit Verteidiger und Forscher das Problem auf ungepatchten Instanzen überprüfen können, die ihnen gehören oder für die sie explizit autorisiert sind.
| CVE | CVE-2026-46394 |
| Komponente | HAXcms PHP Backend – system/backend/php/lib/Git.php |
| Schwachstelle | OS Command Injection (CWE-78) |
| Schweregrad | Hoch – CVSS 3.1 7.2 eigenständig / 8.1 verkettet mit Pfad-Traversal |
| Status | Im Upstream behoben. Betrifft Versionen vor dem Patch. |
| Projekt | elmsln/HAXcms |
| Melder | Shreyas Challa ([email protected]) |
Die Git.php-Bibliothek im HAXcms PHP Backend erstellt Shell-Befehlszeichenketten durch
Verkettung nicht bereinigter Parameter und übergibt sie direkt an
proc_open(). Von den 17 Funktionen, die Shell-Befehle ausführen, verwendet nur
eine (commit()) escapeshellarg(). Die übrigen 15 interpolieren
Aufrufereingaben direkt in die Befehlszeichenkette.
Jeder Wert, der Shell-Metazeichen (&, ;, |, $(), Backticks) enthält und
eine dieser Funktionen erreicht, führt zur beliebigen Ausführung von
Betriebssystembefehlen als Web-Server-Benutzer.
Die einzige korrekt maskierte Funktion ist der deutlichste Beweis dafür, dass die Maskierung bekannt war und einfach überall sonst weggelassen wurde.
Jede anfällige Funktion durchläuft run() → run_command() → proc_open():
// Git.php:408-411 - erstellt eine rohe Befehlszeichenkette
public function run($command) {
return $this->run_command(Git::get_bin() . " " . $command);
}
// Git.php:383 - führt sie über die System-Shell aus
$resource = proc_open($command, $descriptors, $pipes, $this->repo_path, $env);
Anfälliges Beispiel im Vergleich zur einen sicheren Funktion:
// Git.php:574 - ANFÄLLIG (keine Maskierung)
public function create_branch($branch) {
return $this->run("branch $branch");
}
// Git.php:496 - SICHER (beweist, dass der Autor das Muster kannte)
public function commit($message = "") {
return $this->run("commit -av -m " . escapeshellarg($message));
}
| Funktion | Zeile | Shell-Befehl | Maskiert? |
|---|---|---|---|
create_branch($branch) | 574 | branch $branch | NEIN |
delete_branch($branch) | 588 | branch -d $branch | NEIN |
checkout($branch) | 663 | checkout $branch | NEIN |
merge($branch) | 677 | merge $branch --no-ff | NEIN |
push($remote, $branch) | 785 | push $remote $branch $flags | NEIN |
pull($remote, $branch) | 799 | pull $remote $branch | NEIN |
log($format) | 813 | log --pretty=format:"$format" | NEIN |
show($commit, $format) | 830 | show --pretty=format:"$format" $commit | NEIN |
list_tags($pattern) | 763 | tag -l $pattern | NEIN |
clone_to($target) | 512 | clone --local $repo $target | NEIN |
clone_from($source) | 527 | clone --local $source $repo | NEIN |
clone_remote($source) | 543 | clone $source $repo | NEIN |
set_remote($dest, $url) | 460 | remote add $dest $url | NEIN |
rm($files) |
Im ausgelieferten Code werden diese Funktionen mit Werten aufgerufen, die aus Server-/Site-Konfigurationen stammen und nicht direkt aus Anfragekörpern, daher wird die Ausnutzung durch Verkettung realisiert:
saveOutline-Pfad-
Traversal, um die site.json einer Site zu überschreiben und Metazeichen in
metadata.site.git.branch einzuschleusen. Der nächste gitCommit()-Aufruf
führt push('origin', $branch) in HAXCMSSite.php:584 aus und führt so die Nutzlast aus.create_branch() (Operations.php:2762) oder set_remote()
(HAXCMSSite.php:625).Der PoC steuert die echte Git.php-Bibliothek direkt an: Er erstellt ein
Wegwerf-Git-Repository, ruft create_branch() mit einer Nutzlast auf, die ein
Shell-Befehlstrennzeichen verwendet, und bestätigt die Ausführung, indem er eine
Beweisdatei auf der Festplatte überprüft. Er räumt selbstständig auf.
git im PATHgit 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
Weisen Sie den PoC auf die Git.php aus Ihrem HAXcms-Klon hin (Umgebungsvariable
oder erstes Argument); er erkennt außerdem automatisch haxcms-php/, das
daneben platziert ist:
# Option A - Umgebungsvariable
HAXCMS_PHP=../HAXcms/haxcms-php/system/backend/php/lib/Git.php php poc_git_cmdi.php
# Option B - CLI-Argument
php poc_git_cmdi.php ../HAXcms/haxcms-php/system/backend/php/lib/Git.php
Funktioniert sowohl unter Unix (;-Trennzeichen) als auch Windows (&-Trennzeichen);
der PoC wählt die passende Nutzlast für das Host-Betriebssystem automatisch aus.
================================================================
HAXcms Git.php - OS Command Injection (CWE-78)
================================================================
SCHRITT 3: OS-Befehl via create_branch() einschleusen
Nutzlast: test & echo COMMAND_INJECTION_PROOF > "...\PWNED.txt"
SCHRITT 4: Überprüfen, ob der eingeschleuste Befehl ausgeführt wurde
DATEI GEFUNDEN!
Inhalt: COMMAND_INJECTION_PROOF
BEFEHLSEINSCHLEUSUNG BESTÄTIGT.
Wenden Sie escapeshellarg() auf jeden Parameter in allen 15 Funktionen an:
// VORHER
public function create_branch($branch) {
return $this->run("branch " . $branch);
}
// NACHHER
public function create_branch($branch) {
return $this->run("branch " . escapeshellarg($branch));
}
Tiefenverteidigung – validieren Sie Werte, bevor sie die Git-Ebene erreichen:
function validateBranchName($branch) {
return preg_match('/^[a-zA-Z0-9._\/-]+$/', $branch) && strpos($branch, '..') === false;
}
Aktualisieren Sie auf die neueste HAXcms-Version, die den Upstream-Fix enthält.
Dieses Problem wurde den HAXcms-Maintainern gemeldet und vor der Veröffentlichung behoben. Der PoC wird erst freigegeben, nachdem ein Patch verfügbar war. Verwenden Sie ihn ausschließlich gegen Systeme, die Ihnen gehören oder für die Sie ausdrücklich autorisiert sind.
Dieses Material wird für defensive Forschung, Bildung und autorisierte
Sicherheitstests bereitgestellt. Die Ausführung gegen Systeme ohne
ausdrückliche Erlaubnis kann illegal sein. Sie sind allein dafür verantwortlich,
alle geltenden Gesetze einzuhalten und vor dem Test eine Autorisierung
einzuholen. Bereitgestellt „wie besehen“ ohne Gewährleistung (siehe LICENSE).
| 479 |
rm $files |
| NEIN |
add_tag($tag, $msg) | 749 | tag -a $tag -m $msg | $tag: NEIN, $msg: ja |
commit($message) | 496 | commit -av -m $message | JA (einzige sichere) |