
PoC zur Rechteausweitung ohne Authentifizierung für WordPress Events Manager < 7.4.1; ermittelt kollidierende Post-/Benutzer-IDs und stuft Zielkonten über REST oder wp-admin zu Administratoren hoch.
| Produkt | Events Manager (WordPress-Plugin) |
| Betroffene Versionen | 7.1.0 – 7.4.0.x |
| Behobene Version | 7.4.1 |
| Schwachstelle | CWE-269: Unsachgemäße Rechteverwaltung |
| Schweregrad | CVSS 3.1: 9.8 (Kritisch) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| WPVDB ID | 82767ce2-01e4-46ad-a52b-72d3ab2049bd |
| Ursprünglicher Forscher | Jakub Herman |
| Write-up & PoC | ghostpel |
poc.py).Events Manager in den Versionen 7.1.0 bis 7.4.0.x enthält eine Schwachstelle zur Rechteausweitung, die es einem vollständig nicht authentifizierten Angreifer ermöglicht, jedes Benutzerkonto zu übernehmen, dessen ID mit der ID eines eigenen Beitrags des Plugins kollidiert (event / location / event-recurring / location-recurring). Auf Websites mit aktivierten Gastbuchungen (Standard) kann die Kollision erzwungen werden: Jede Gastbuchung erzeugt ein echtes Benutzerkonto und erhöht den Auto-Increment-Zähler von wp_users um eins, sodass ein Angreifer den Benutzer-ID-Raum gezielt bis zu einer Event-/Location-Beitrags-ID „durchwandern“ kann.
Die Ursache: Der map_meta_cap-Filter des Plugins verwirft die von WordPress bereits berechnete Capability-Liste ($caps = []) für jede Meta-Capability, sobald die Objekt-ID der Capability zufällig zu einem Event-/Location-Beitrag aufgelöst wird — einschließlich WordPress-Core-Capabilities wie edit_user, delete_user, promote_user und remove_user. Eine leere Capability-Liste bedeutet „keine Capability erforderlich“ — also Erlaubnis für alle, auch für abgemeldete Benutzer.
Folgen (alle ohne Authentifizierung, über die WP-REST-API): Das Passwort eines beliebigen kollidierenden Kontos ändern, es zu administrator hochstufen oder es löschen.
Analysierte Version: 7.4.0.1 (anfällig) — per Diff gegen 7.4.1 (behoben) verglichen.
| Version | Status |
|---|---|
| ≤ 7.0.5 | Nicht betroffen (das alte em_map_meta_cap verarbeitet nur EMs eigene Capabilities) |
| 7.1.0 – 7.4.0.x | Anfällig (das Archetypen-System mit dem fehlerhaften map_meta_cap wurde in 7.1.0 eingeführt) |
| 7.4.1 | Behoben |
map_meta_cap leert $capsclasses/em-archetypes.php (Version 7.4.0.1):
| Zeile | Code | Rolle |
|---|---|---|
:33 | add_filter( 'map_meta_cap', [ static::class, 'map_meta_cap'], 10, 4 ); | Globaler, bedingungsloser Filter — läuft bei jeder WordPress-Meta-Capability-Prüfung, einschließlich der Core-Prüfungen und derer für abgemeldete Benutzer |
:547 | if ( !empty( $args[0] ) ) { | Das Objekt der Capability wird als Beitrags-ID behandelt |
:548 | $post = get_post($args[0]); | ID-Kollision: Die Ziel-Benutzer-ID (für Caps wie edit_user) wird als Beitrags-ID behandelt |
:551 | `if( empty($post->post_type) | |
:563 | `if ( !empty( $c['read'][$post->post_type] ) | |
:564–565 | $caps = []; | Die Capability-Liste wird bedingungslos verworfen — obwohl es sich bei der angeforderten Cap nicht um eine Archetypen-Cap read/edit/delete_event handelt |
:568/577/584 | if/elseif-Zweige | $caps wird nur neu befüllt, wenn $cap exakt einer Archetypen-Meta-Cap entspricht; für edit_user, delete_user, promote_user, remove_user greift kein Zweig → $caps bleibt leer |
:597 | return $caps; | Leeres Array = „keine Capability erforderlich“ = ERLAUBT für jeden, einschließlich Benutzer-ID 0 |
Konsequenz: Jede Prüfung von current_user_can('edit_user', X) / delete_user / promote_user / remove_user liefert TRUE, sobald X der ID eines Event-/Location-Beitrags entspricht. Das Plugin „verwirft die Zugriffskontrollentscheidungen, die WordPress bereits getroffen hatte“ — genau wie von WPScan beschrieben.
Per Diff von 7.4.0.1 gegen 7.4.1 verifiziert: Der Reset ist jetzt pro Zweig durch einen exakten Capability-Abgleich abgesichert (z. B. && $c['read'][$post->post_type] == $cap), sodass $caps nur noch geleert wird, wenn die angeforderte Capability tatsächlich eine Archetypen-Meta-Cap ist. Patch-Kommentar: „Das Zurücksetzen bei jeder Cap mit Objekt leerte die Anforderungsliste für unabhängige Caps (z. B. edit_user, promote_user), was sich als Erlaubnis liest.“
Die REST-Users-Endpunkte (/wp-json/wp/v2/users/{id}) haben kein globales Login-Gate — die Zugriffskontrolle erfolgt ausschließlich über Permission-Callbacks, die alle durch denselben map_meta_cap-Filter laufen:
| Aktion | Endpoint / Core-Funktion | Umgangene Capability |
|---|---|---|
| Passwort des Zielkontos ändern | PUT /wp-json/wp/v2/users/{id} mit {"password":"..."} → wp_update_user() (interne edit_user-Prüfung) | edit_user |
| Konto zum Administrator hochstufen | PUT /wp-json/wp/v2/users/{id} mit {"roles":["administrator"]} | promote_user |
| Ein Konto löschen | DELETE /wp-json/wp/v2/users/{id}?reassign=... → wp_delete_user() (interne delete_user-Prüfung) | delete_user |
| (Multisite) Benutzer vom Blog entfernen | remove_user | remove_user |
Nebeneffekt: edit_comment ist ebenfalls betroffen, wenn eine Kommentar-ID zufällig einer Event-/Location-Beitrags-ID entspricht (die wp_comments-Tabelle teilt sich den Zahlenraum).
Die Kollision existiert, weil wp_users.ID und wp_posts.ID unabhängige Auto-Increment-Sequenzen sind, die zwangsläufig überlappen. Gastbuchungen erzwingen sie:
em-install.php:896 — dbem_bookings_anonymous = 1: Gastbuchungen standardmäßig aktiviert; :871 dbem_bookings_registration_disable = 0 (Registrierung aktiviert).em-actions.php:340-344 — booking_add steht in $booking_nopriv_actions → ohne Login aufrufbar (über wp_ajax_nopriv_booking_add, Priorität 999999, Zeilen :817-830, oder wp_loaded :11).em-actions.php:360-375 — Ablauf von booking_add: em_verify_nonce('booking_add') → get_post() → validate() → em_booking_add_registration() → $EM_Bookings->add(). (Das Nonce dient nur dem CSRF-Schutz — das booking_add-Nonce wird im öffentlichen Buchungsformular ausgegeben, sodass es jeder erhalten kann.)em-functions.php:405-417 — Gast-Zweig: em_register_new_user($user_data) mit der E-Mail-Adresse des Angreifers.em-functions.php:510 — wp_insert_user($user_data) → Der Auto-Increment-Zähler von wp_users erhöht sich bei jeder Gastbuchung um 1 → der Angreifer kontrolliert die Wachstumsrate des Benutzer-ID-Zählers, bis er auf der gewünschten Event-/Location-Beitrags-ID landet (WPScan: „Jede Gastbuchung erzeugt ein echtes Benutzerkonto und erhöht den Benutzer-ID-Zähler um eins“).