
CVE-2026-87902-Detektor. WordPress get_page_template LFI-Klasse. Nur-Erkennung. Autorisierter Laboreinsatz.
CVE-2026-87902-Detektor für WordPress Core.
get_page_template() kann so gesteuert werden, dass die Auflösung des Seitentemplates eine lesbare lokale .php-Datei außerhalb des aktiven Themes einschließt. WPSniper fingerprintet die Website, wählt eine veröffentlichte page_id, prüft die Include-Klasse und gibt nur dann VULN aus, wenn ein starkes PEAR-Banner eindeutig zum Probe-Body gehört.
Nur Erkennung. Keine Webshell. Kein pearcmd config-create. Keine OS-Befehlsausführung.
python3 WPSniper.py -u https://lab.wordpress.local --shell
Pipeline:
subfinder -d lab.example -silent | httpx -silent | python3 WPSniper.py -t 8
Definierter Geltungsbereich. Eigenes Lab. Das ist die gesamte Lizenz zum Ausführen.
WordPress bildet den Seitentemplate-Namen aus der URL-abgeleiteten, URL-dekodierten pagename-Query-Variable:
page-{$pagename}.php
locate_template() schließt diese Datei dann ein. Bei betroffenen Builds wird der aufgelöste Pfad nicht dazu gezwungen, innerhalb eines erlaubten Theme-Verzeichnisses zu bleiben. Ein doppelt kodierter Traversal in pagename übersteht sanitize_title weit genug, damit get_page_template() ihn einmal dekodiert und aus dem Theme-Baum herausläuft.
Zwei Vorbedingungen stehen vor einem geschlossenen Include:
page- beginnt (WordPress dokumentiert page-templates/ — Twenty Twelve, Twenty Fourteen, Neve, Hestia, Sydney und andere)..php-Ziel existiert für das Web-Server-Konto. Der Detektor verwendet Standard-PEAR-CLI-Banner als Include-Oracle. Er schreibt keines.RCE ist ein möglicher Folgeschritt, wenn diese Bedingungen plus eine beschreibbare/ausführbare Gadget-Zeile zusammenkommen. Dieser Folgeschritt ist nicht in diesem Repository.
Finder-Credit für die CVE: Robert (ressl) via WordPress HackerOne. Advisory: GHSA-7hp8-65ch-5whp.
| Schritt | Aktion | Signal |
|---|---|---|
| 1 | Home + Generator + /feed/ | WordPress? Version? Theme-Slug? |
| 2 | REST /wp-json/wp/v2/pages oder page_id= im HTML | Eine veröffentlichte Seite, damit der Template-Pfad tatsächlich ausgeführt wird |
| 3 | GET /wp-content/themes/{slug}/page-templates/ | 200 / 401 / 403 = Verzeichnis existiert |
| 4 | Baseline ?page_id=N vs. Probe pagename= | Body-Digest + eindeutige starke PEAR-Token |
Versionstabelle ist eingebaut. 4.7.0–7.1.1 sind das betroffene Fenster. Gepatchte Punkte: 7.1.2, 7.0.6, 6.9.9, 6.8.10 … zurück bis 4.7.37.
Eine Marketing-Seite, die in einem Blogbeitrag „pearcmd“ erwähnt, ist kein Treffer.
VULN nur wenn all dies zutrifft:
?page_id=-DigestPEAR Version:, Usage: pear, PEAR_Config, Commands for pear, config-create, DEPRECATED: PEAR commands, pear.php)pearcmd / PEAR allein wird verworfen, besonders wenn es bereits im Baseline-HTML standINFO = betroffene Version und/oder page-templates-Verzeichnis, Include nicht geschlossen. Kein Critical auf INFO melden.
SAFE = gepatchter Branch, oder Include identisch zur Baseline.
SKIP = kein WordPress, ungültige URL.
/etc/passwd ist das falsche Oracle für diese CVE. locate_template() hängt .php an. Der interaktive passwd-Befehl existiert, damit du das selbst sehen kannst. Eine erscheinende root:x:0:0:-Stanza ist ungewöhnlich und muss manuell verifiziert werden.
python3 -m pip install -r requirements.txt
python3 WPSniper.py -u https://lab.wordpress.local
Benötigt requests.
| Flag | Bedeutung |
|---|---|
-u URL | Einzelnes Ziel |
-l file | URL-Liste |
| stdin | subfinder | httpx | WPSniper |
-t N | Threads bei einer Liste (Standard 6) |
-q | Ruhige Zeilen + Zusammenfassung |
--shell | Interaktive Probe bei einem einzelnen -u |
--timeout | Sekunden (Standard 14) |
--shell wird bei einer Pipeline ignoriert. Das ist beabsichtigt.
python3 WPSniper.py -u https://lab.wordpress.local --shell
[email protected] ▶
1 fp version / theme / patched?
2 pages REST published pages
3 theme page-templates directory
4 probe PEAR include + baseline diff (no write)
5 diff same, print Δ + tokens
6 passwd try …/etc/passwd (this class includes *.php)
7 include P include a .php path without suffix
8 save last body → /tmp/wpsniper-probe.html
9 help
0 exit
Jede Probe gibt die vollständige URL und ein Copy-Paste-curl aus. Verwende das im Report. Erfinde keine zweite Anfrage.
7 include ist für eine autorisierte Lab-Datei, die du bereits platziert hast. Der Beispielname im Hilfetext ist ein Witness-Marker, kein Dropper.
WPSniper v1.3 CVE-2026-87902 get_page_template LFI
[radar] target https://lab.wordpress.local
[radar] generator=6.8.3 theme=twentytwelve status=affected
[radar] page_id=2
[radar] theme dir /wp-content/themes/twentytwelve/page-templates/ → 403
VULN lab.wordpress.local unique=['PEAR Version:','Usage: pear'] Δlen=+18420
patched 7.1.2 · 7.0.6 · 6.8.10 · backports to 4.7.37
Der Host auf dieser Seite ist ein Lab-Label. Live-Kundenhostnamen gehören nicht in ein öffentliches Standbild.
Upgrade auf 7.1.2 oder den Backport für deinen Branch:
7.0.6 · 6.9.9 · 6.8.10 · 6.7.9 · 6.6.9 · 6.5.12 · 6.4.12 · 6.3.12 · 6.2.13 · 6.1.14 · 6.0.16 · 5.9.18 … bis hinunter zu 4.7.37.
7.1.2 erfordert außerdem, dass der aufgelöste Template-Pfad innerhalb eines erlaubten Theme-Verzeichnisses bleibt. Das ist der eigentliche Fix, keine WAF-Regel.
pearcmd config-create, kein system()-Wrapper/etc/passwd als primäre BestätigungWenn du einen Finding brauchst: hänge das curl an, das WPSniper bereits ausgegeben hat, die eindeutigen starken Token und die Baseline-Digest-Abweichung.
Nur autorisiertes Sicherheitstesting. Dies gegen einen Host auszuführen, den du nicht besitzt oder nicht schriftlich genehmigt hast, ist dein Problem, nicht das des Tools.
mitsec · Yunus Emre Öztaş