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
wp2shell — PoC for CVE-2026-63030 + CVE-2026-60137, AKA WP2Shell | Kitploit
Tools/GitHubGitHub/crypto-cat/wp2shell
Vulnerability ScannersCode AnalysisExploitationWeb SecurityLearning & Education
GitHubcrypto-cat/wp2shell

wp2shell

PoC for CVE-2026-63030 + CVE-2026-60137, AKA WP2Shell

Repository anzeigen
3vor 1 MonatNoch 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

wp2shell

Pre-Authentication Remote Code Execution für WordPress 6.9.0–6.9.4 und 7.0.0–7.0.1.

Verkettet CVE-2026-63030 (Batch-Routen-Verwirrung SQLi) mit CVE-2026-60137 (Customizer-Änderungssatz-Wiedereintritt), um eine nicht authentifizierte Administratorerstellung und Betriebssystem-Befehlsausführung zu erreichen. Kein Passwort-Knacken erforderlich.

wp2shell demo

Props an hashkitten für die Entdeckung, lesen Sie die vollständige technische Analyse von SLCyber hier.

Die Schwachstelle

Der REST-API-Batch-Prozessor von WordPress (serve_batch_request_v1) hat einen Off-by-One-Indizierungsfehler: Wenn wp_parse_url() bei einem Unteranfragepfad fehlschlägt, wird das resultierende WP_Error zu $validation[] hinzugefügt, aber nicht zu $matches[]. Dies desynchronisiert die beiden Arrays – jede nachfolgende Anfrage wird unter dem falschen Handler ausgeliefert.

Durch Verschachteln eines sorgfältig strukturierten Batches innerhalb eines anderen Batches kann ein Angreifer:

  1. Eine Anfrage, die durch das Schema eines Endpunkts validiert wurde, über den Callback eines völlig anderen Endpunkts leiten
  2. Unsanitized SQL durch author__not_in injizieren (der String→Array-Cast überspringt absint())
  3. UNION SELECT verwenden, um den Objekt-Cache von WordPress mit gefälschten Beitragsobjekten zu vergiften
  4. Eine automatische Veröffentlichung eines Changesets auslösen, die Berechtigungen erhöht, und dann mit Admin-Kontext in die REST-API wiedereintreten

Sobald die Einrichtung abgeschlossen ist (Tabellenpräfix und Admin-ID ermittelt), wird die Eskalationsnutzlast in einer einzigen HTTP-Anfrage ausgelöst – Cache-Vergiftung, Berechtigungserhöhung und Benutzererstellung erfolgen serverseitig in einem Round-Trip.

Wie die Kette funktioniert

root@kitploit:~
HTTP POST /batch/v1
    │
    ▼
┌─ Äußerer Batch ───────────────────────────────────────────────────────┐
│                                                                     │
│  [0] ///                  → Parse-Fehler, nicht zu $matches hinzugefügt │
│  [1] POST /wp/v2/posts    → $matches[0] (Posts Handler)             │
│  [2] POST /batch/v1       → $matches[1] (Batch Handler)             │
│                                                                     │
│  Desync: request[1] dispatch via $matches[1]                        │
│          POST /wp/v2/posts body interpretiert als Batch → inner fire │
│                                                                     │
└──────────────────────────────────────┬──────────────────────────────┘
                                       │
    ┌──────────────────────────────────┘
    ▼
┌─ Innerer Batch ───────────────────────────────────────────────────────┐
│                                                                     │
│  [0] ///                            → Parse-Fehler (Desync)          │
│  [1] GET  /wp/v2/widgets?UNION...   → dispatch durch Posts Handler  │
│          ▲ WP_Query führt UNION aus, vergiftet Objekt-Cache         │
│          ▲ the_content rendert [embed] → oEmbed → Hierarchie Loop 1 │
│              → changeset veröffentlicht → Admin-Kontext gesetzt     │
│              → nav_menu_item UPDATE → Hierarchie Loop 2              │
│                  → parse_request → REST-Wiedereintritt ─────────────┐│
│                                                               │    │
│  [2] GET  /wp/v2/posts              (Categories Handler)      │    │
│  [3] GET  /wp/v2/categories         (Users Handler)           │    │
│  [4] POST /wp/v2/users  {body}  ◄── Wiedereintritt mit Admin ─────┘│
│          ▲ Desync gleicht dies mit dem Users Handler ab             │
│          ▲ Admin-Kontext → Benutzer erstellt → die()                │
│  [5] POST /wp/v2/users  {}          (Desync-Spacer)                 │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Cache-Vergiftung (7 gefälschte Beiträge via UNION):

  • Ein Auslöser-Beitrag mit einem [embed]-Shortcode in seinem Inhalt
  • Ein Changeset-Beitrag (customize_changeset, Status future, Datum in der Vergangenheit)
  • Ein äußerer Schleifenpartner (parent=changeset, erzeugt Loop 1)
  • Ein oEmbed-Ziel (dynamische Anti-Rekursions-ID, parent=changeset, leerer Inhalt)
  • Ein Navigationsmenü-Element-Beitrag (vergiftet als post_type=nav_menu_item für den is_nav_menu_item-Check)
  • Ein Wiedereintritts-Beitrag (post_type=request, post_status=parse, parent=inner)
  • Ein innerer Schleifenpartner (parent=re-entry, erzeugt Loop 2)

Ausführungsablauf:

  1. UNION vergiftet den Objekt-Cache mit allen 7 gefälschten Beiträgen
  2. Der Posts Handler rendert den Inhalt des Auslöser-Beitrags → [embed]-Shortcode feuert
  3. oEmbed-Cache-Suche findet einen Hintergrundbeitrag mit leerem Inhalt → fällt durch auf wp_update_post
  4. wp_update_post liest das gecachte Changeset (parent=outer) → Hierarchieprüfung erkennt Loop 1
  5. Fix-up schreibt Changeset in die DB mit Status future → automatisch in publish umgewandelt
  6. _wp_customize_publish_changeset feuert → wp_set_current_user(admin_id) → Admin-Kontext aktiv
  7. Changeset verarbeitet nav_menu_item[real_id] – Cache sagt Typ=nav_menu_item → UPDATE-Pfad
  8. object_id löst einen gecachten Beitrag mit post_parent=re-entry auf → wp_update_post auf echtem Beitrag
  9. Hierarchieprüfung (nicht-null $post_id) erkennt Loop 2 (re-entry ↔ inner)

Eine Anti-Rekursions-MySQL-Sitzungsvariable (@_wp2s) stellt sicher, dass die Kette genau einmal feuert und sich nicht wiederholt.

Funktionen

  • Drei Extraktionsmodi mit automatischer Erkennung: UNION (1 Anfrage/Wert), fehlerbasiert via EXTRACTVALUE (~30 Zeichen/Anfrage), boolean-blind binäre Suche (~7 Anfragen/Zeichen)
  • Vollständige Pre-Auth RCE – keine Anmeldedaten, kein Knacken, Eskalation in einem einzigen Round-Trip
  • Auto-Erkennung – Tabellenpräfix via INFORMATION_SCHEMA, Admin-Benutzer-ID via Capabilities-Meta
  • Post-Exploitation – Plugin-Webshell mit Token-Auth, CWD-verfolgende interaktive Shell, Datei-Lesen/Schreiben
  • Aufräum-Modus – --cleanup löscht den erstellten Benutzer und entfernt die Webshell beim Beenden
  • Keine Abhängigkeiten – nur Stdlib, einzelne Datei, läuft auf Python 3.8+

Installation

root@kitploit:~
git clone https://github.com/Crypto-Cat/wp2shell.git
cd wp2shell
chmod +x wp2shell.py

Kein pip install, kein virtualenv. Es ist eine Datei.

Verwendung

Prüfen, ob ein Ziel verwundbar ist

root@kitploit:~
# Passiver boolean-Orakel-Test
python3 wp2shell.py check http://target.com

# Auch mit Timing und UNION bestätigen
python3 wp2shell.py check http://target.com --confirm-timing --confirm-union

Daten extrahieren

root@kitploit:~
# Wählt automatisch die schnellste Technik aus (UNION > error > blind)
python3 wp2shell.py read http://target.com --preset users
python3 wp2shell.py read http://target.com --preset secrets
python3 wp2shell.py read http://target.com --query "SELECT @@version"

# Erzwinge eine bestimmte Technik
python3 wp2shell.py read http://target.com --technique blind --preset users

# Tabellenpräfix automatisch erkennen
python3 wp2shell.py read http://target.com --auto-prefix --preset users

Vollständige Ausnutzung

root@kitploit:~
# Exploitieren und in interaktive Shell einsteigen
python3 wp2shell.py exploit http://target.com -i

# Exploitieren, einen Befehl ausführen, aufräumen
python3 wp2shell.py exploit http://target.com -c "cat /etc/passwd" --cleanup

# Auto-Erkennung überspringen, wenn das Präfix bekannt ist
python3 wp2shell.py exploit http://target.com --prefix wp_ --no-discover -i

# Durch einen Proxy (Burp, mitmproxy usw.)
python3 wp2shell.py exploit http://target.com --proxy http://127.0.0.1:8080 -i

Authentifizierte Shell (mit bestehenden Anmeldedaten)

root@kitploit:~
python3 wp2shell.py shell http://target.com --user admin --password 'P@ssw0rd' -i

Anforderungen für vollständiges RCE

Die check- und read-Befehle funktionieren auf jedem betroffenen Ziel. Die exploit-Kette hat drei zusätzliche Anforderungen:

Wenn das Ziel Redis oder Memcached als Objekt-Cache verwendet, ist split_the_query unabhängig von per_page erzwungen und UNION-Zeilen werden beim Nur-ID-Abruf verworfen. Der read-Befehl funktioniert trotzdem (Blind-Extraktion benötigt nicht, dass UNION im Cache überlebt), aber exploit wird fehlschlagen.

Betroffene Versionen

BranchVerwundbarBehebung
6.9.x6.9.0 – 6.9.46.9.5
7.0.x7.0.0 – 7.0.17.0.2

Der Patch fügt $matches[] = $single_request; für Fehlerfälle hinzu (behebt den Off-by-One) und eine Wiedereintritts-Sperre in serve_request().

Architektur

root@kitploit:~
wp2shell.py (Einzeldatei, ~1650 Zeilen)
├── Client          HTTP-Transport mit Batch-URL-Aushandlung
├── Desync          Verschachtelter Batch-Nutzlastaufbau
├── BlindExtractor  Boolean-Binärsuche (universal)
├── UnionExtractor  In-Band via gefälschtem post_title (schnellste)
├── ErrorExtractor  EXTRACTVALUE-basiert (mittel)
├── PoisonGraph     Hierarchieschleifen-Struktur für Cache-Vergiftung
├── Exploiter       Kettenorchestrierung (Seed → Extract → Escalate)
└── AdminSession    Authentifizierte Sitzung, Webshell, Aufräumen

Technische Details

Warum /wp/v2/widgets als Quellroute?

Der Widgets-Controller registriert per_page, orderby oder author_exclude nicht in seinem Endpunkt-Schema. Diese Parameter passieren die Validierung unverändert (unbekannte Parameter werden vom Schema-Validator ignoriert). Wenn die Desynchronisation diese Anfrage durch den Posts-Controller leitet, fließen diese rohen Werte direkt in WP_Query.

Warum per_page=500?

class-wp-query.php:3375 – split_the_query erfordert !empty($limits) && posts_per_page < 500. Mit per_page=500 ist die Bedingung 500 < 500 falsch, also ist split_the_query deaktiviert. Die vollständige Abfrage (einschließlich UNION) wird als einzelne Anweisung ausgeführt, und alle injizierten Zeilen überleben im Ergebnissatz und Cache.

Warum nav_menu_item[real_id] (positive ID)?

Die Verwendung einer positiven Beitrags-ID betritt den UPDATE-Pfad bei nav-menu.php:614, der wp_update_post mit einem nicht-null $post_id aufruft. Dies ist entscheidend, da wp_check_post_hierarchy_for_loops bei post.php:8070 frühzeitig zurückkehrt, wenn $post_id = 0 (neue Beiträge). Der Cache wird für diese ID mit post_type=nav_menu_item vergiftet, sodass is_nav_menu_item() den Typ-Check bei nav-menu.php:426 besteht. Der UPDATE-Pfad löst dann die Hierarchieprüfung aus, die Loop 2 erkennt.

Warum zwei Hierarchieschleifen?

Loop 1 (changeset ↔ outer) löst die Changeset-Veröffentlichung aus und setzt den Admin-Kontext. Loop 2 (re-entry ↔ inner) feuert während des Admin-Zeitfensters (innerhalb des save()-Aufrufs der nav_menu_item-Einstellung in der Changeset-Veröffentlichungsschleife) und löst parse_request → REST-Wiedereintritt aus. Die Schleifen sind unabhängig, da die Reparatur von Loop 2 den Wiedereintrittsbeitrag während des Admin-Zeitfensters in Zeile 3581 in die DB schreiben muss – vor dem Zurücksetzen in Zeile 3589.

Haftungsausschluss

Dieses Tool wird für autorisierte Sicherheitstests und Forschungszwecke veröffentlicht. Verwenden Sie es nur gegen Systeme, die Sie besitzen oder für die Sie eine ausdrückliche schriftliche Genehmigung zum Testen haben. Unberechtigter Zugriff auf Computersysteme ist illegal.

Credits

Forschung und Entwicklung von CryptoCat.

Tool herunterladen
  • Fix-up ruft wp_update_post(re-entry) auf → schreibt Typ=request, Status=parse in DB
  • wp_transition_post_status feuert do_action("parse_request") → rest_api_loaded() → serve_request()
  • REST-API tritt wieder ein, verarbeitet den gesamten Batch mit Admin-Rechten erneut
  • POST /wp/v2/users im hinteren Teil erfolgreich → Administrator erstellt → die()
  • AnforderungWarumStandard-WP?
    Mindestens ein veröffentlichter BeitragoEmbed benötigt eine lokale URL, um Embed-Verarbeitung auszulösenJa (Hallo Welt)
    Kein persistenter Objekt-CacheSplit-the-Query muss deaktiviert sein, damit UNION-Zeilen überlebenJa (Datei-Cache Standard)
    REST-API erreichbarWiedereintritt via parse_request benötigt den REST-ServerJa
    Direktes Dateisystem-SchreibenPlugin-Upload benötigt FS_METHOD=direct oder PHP, das wp-content besitztJa (die meisten Hosts)