WordPress-XSS-Kampagne installiert versteckte Admin-Konten
Eine WordPress-XSS-Kampagne, die erstmals am 4. Oktober 2026 von Patchstack beobachtet wurde, nutzt gespeicherte Cross-Site-Scripting-Schwachstellen in zwei nicht verwandten Plugins, um ein Administratorkonto zu installieren, das Website-Betreiber in wp-admin nicht sehen können. Die gleiche JavaScript-Nutzlast, die über beide Schwachstellen ausgeliefert wird, wird von imgcdn1.com geladen und wurde von Patchstack abgerufen und analysiert. Es handelt sich um ein Post-Exploitation- und Persistenz-Implantat, das im Browser eines angemeldeten Administrators ausgeführt werden soll, diese Administratorsitzung missbraucht, um ein bösartiges Plugin zu installieren, einen versteckten Administrator zu erstellen, eine Backdoor-Anmelde-URL hinzuzufügen und Ergebnisse an die vom Angreifer kontrollierte Infrastruktur zu melden.
Die erste ausgenutzte Schwachstelle ist CVE-2026-93836, ein nicht authentifiziertes gespeichertes XSS in WPC Product Bundles für WooCommerce bis Version 8.6.6. Die Schwachstelle ermöglicht es, dass ein Mengenwert, der mit einer gültigen Zahl beginnt, die Validierung besteht und gleichzeitig vom Angreifer kontrolliertes Markup enthält. Der Wert wird in WooCommerce-Bestellmetadaten gespeichert und später unsicher gerendert. Patchstack sah am 4. Oktober Anfragen, die die Nutzlast über den Parameter woosb_ids[…][qty] lieferten, mit einem numerischen Präfix gefolgt von einem Script-Tag, das x.js von imgcdn1.com lädt. Am nächsten Tag erschien dieselbe Nutzlast über CVE-2026-94504 in Ninja Forms bis Version 3.15.3. Ninja Forms speicherte Textarea-Eingaben und konnte sie ohne sichere HTML-Kodierung im alten administrativen Einreichungs-Editor rendern. Version 3.15.4 verbesserte die Ausgabe-Escaping. Der Angreifer übermittelte die Nutzlast über den normalen Ninja-Forms-AJAX-Endpunkt unter /wp-admin/admin-ajax.php mit action=nf_ajax_submit, wobei ein Bild-Tag mit einem onerror-Handler eingefügt wurde, der ein Script-Element erstellt und dasselbe x.js lädt. Die beiden Loader unterscheiden sich, weil die Angreifer sich an jeden anfälligen Kontext anpassen, aber die zentralisierte zweite Stufe verbindet beide Versuche zu einer Kampagne.
Das abgerufene x.js ist ein zweckgebundenes WordPress-Post-Exploitation- und Persistenz-Skript, leicht verschleiert mit kodierten String-Tabellen und indirekten Funktionsaufrufen. Sein Ablauf ist: gespeichertes XSS in wp-admin, Ursprung auflösen, beim Command-and-Control-Server (C2) melden, Plugin installieren, Administrator erstellen, emer-run.php abrufen und zurückmelden. Das JavaScript benötigt keine zweite serverseitige Schwachstelle; es nutzt legitime WordPress-Administrationsfunktionen über die bestehende authentifizierte Sitzung des Administrators.
Die Malware stiehlt niemals das WordPress-Cookie des Administrators. Da das JavaScript im Sicherheitskontext der kompromittierten Website ausgeführt wird, tragen Same-Origin-Anfragen an /wp-admin/ automatisch die Sitzung des angemeldeten Benutzers. Das Skript lädt privilegierte WordPress-Seiten, extrahiert die CSRF-Nonces, die einmaligen Sicherheitstoken, die legitime administrative Aktionen erfordern, und spielt sie erneut ab, um diese Aktionen selbst auszuführen. HttpOnly-Cookies, ein Browserschutz, der JavaScript daran hindert, Cookies zu lesen, helfen nicht, da das Skript das Cookie nie liest; es reitet einfach auf der Sitzung.
Vor jeder Persistenzaktion kontaktiert die Malware https://imgcdn1.com/fz/c.php?xa=check&site=. Die Antwort enthält Statusfelder wie plugin, admin, emer und skip, die es dem C2 ermöglichen zu entscheiden, welche Phasen für ein Opfer bereits erfolgreich waren. Die Malware speichert außerdem den lokalen Ausführungsstatus im Browser unter einem Local-Storage-Schlüssel, der mit __xp_v9_ beginnt, und verfolgt erfolgreiche Phasen als plugin, admin und emer, um schließlich eine abgeschlossene Kompromittierung als all zu markieren. Statusdaten werden mit fetch(), navigator.sendBeacon() und einem Bild-Request-Fallback gesendet, sodass der C2 Ergebnisse auch dann erhält, wenn die Navigation die Ausführung unterbricht.
Mit der Sitzung des Opfers lädt das Skript /wp-admin/plugin-install.php?tab=upload, extrahiert die Upload-Nonce, lädt ein ZIP von https://imgcdn1.com/fz/c.php?xa=pkg herunter und übermittelt es über den eigenen Plugin-Installer von WordPress. Patchstack hat das Paket abgerufen und analysiert. Es installiert sich unter dem Slug wp-smart-thumbnails und enthält vier Dateien: wp-smart-thumbnails.php (20.728 Bytes, gepackter Dropper und Dateimanager), emer-run.php (14.330 Bytes, Persistenz-Installer), readme.txt (46 Bytes, Täuschung) und includes/class-thumb-cache.php (41 Bytes, Täuschung). Das Plugin gibt sich als WP Smart Thumbnails 1.2.4 von „MediaPress Labs“ aus, ein Plugin zum Caching responsiver Thumbnails, aber die Funktionsdatei enthält nur einen ABSPATH-Schutz, und readme.txt besteht aus zwei Zeilen. Alle Dateien sind auf Juli 2026 datiert, Monate vor der Kampagne, was auf absichtliche Rückdatierung hindeutet. Die Haupt-Plugin-Datei beginnt mit einem umgekehrten Schutz: Wenn ABSPATH definiert ist, wird zurückgegeben, sodass die Nutzlast niemals ausgeführt wird, während WordPress das Plugin lädt. Installiert und aktiv tut es nichts; es zündet nur bei einer direkten HTTP-Anfrage, wie der eigene Kommentar des Angreifers sagt.
Unter diesem Schutz befindet sich ein einzelner Base64-Blob. Er wird Base64-dekodiert, mit einem 26-Byte-Schlüssel XOR-verknüpft, umgekehrt, ROT13 unterzogen, zweimal Base64-dekodiert, um zwei Bytes rotiert und mit gzuncompress dekomprimiert, dann gegen eine hartcodierte MD5-Prüfsumme geprüft, bevor er ausgeführt wird. Diese letzte Prüfung ist die eigene Integritätssicherung des Autors, und die von Patchstack entpackte Stufe stimmt damit überein. Anstelle von eval() registriert der Dropper einen benutzerdefinierten Stream-Wrapper und bindet den dekodierten Quellcode über eine dyiv://-URL ein, um Regeln zu umgehen, die auf eval() bei dekodierten Eingaben achten. Die entpackte Stufe ist ungefähr 37 KB groß: ein grafischer Dateimanager mit dem Titel „Moon, tell me if I could“, der Auflisten, Hochladen, Löschen, Umbenennen, mkdir, Lesen und Speichern über eine JSON-API anbietet. Er hat keinerlei Authentifizierung. Kein Passwort, kein Token, keine Berechtigungsprüfung; der einzige Gleichheitstest auf einen Schlüssel ist ein JavaScript-Handler für die Escape-Taste. Es gibt keine Befehlsausführungs-Primitive, aber Hochladen und Speichern können vom Angreifer gelieferte Bytes in jeden beschreibbaren Pfad schreiben, genug, um eine zweite Shell abzulegen.
emer-run.php ist der Ort, an dem dauerhafte Persistenz aufgebaut wird. Über HTTP bootet es WordPress, verlangt current_user_can('administrator') und gibt JSON zurück, weshalb x.js es aus der Administratorsitzung heraus aufruft. Von der Kommandozeile oder WP-CLI überspringt es die Berechtigungsprüfung vollständig. Sein Header-Kommentar sagt „hidden admin + magic login (invoked via XSS admin session). Returns JSON only; drops obfuscated MU-plugins.“ Es tut drei Dinge. Erstens erstellt es ein Administratorkonto, das routinemäßig aussehen soll: ein Benutzername, der zufällig aus einem Wörterbuch von etwa fünfzig harmlosen betrieblichen Wörtern wie support, updater, maintenance und backup gezogen wird, mit einer @wordpress.org-E-Mail-Adresse und einem 16-stelligen Zufallspasswort. Zweitens versteckt es dieses Konto vor dem Website-Betreiber. Das Skript schreibt ein Must-Use-Plugin nach wp-content/mu-plugins/class-wp-query-.php, wobei der Hex-Wert vom Benutzernamen abgeleitet wird. Diese Datei installiert drei Hooks: pre_user_query hängt AND user_login != '' an die SQL-Abfrage der Benutzerliste an; users_list_table_query_args fügt das Konto zu login__not_in hinzu; views_users verringert die Rollenzählungen, die über der Liste angezeigt werden. Das Konto erscheint nicht unter Benutzer → Alle Benutzer, erscheint nicht im Administrator-Filter und wird nicht in den Gesamtzahlen über der Liste gezählt. Es ist ein voll privilegierter Administrator, den der Website-Betreiber nicht sehen kann. Must-Use-Plugins werden bei jeder Anfrage geladen, können nicht über wp-admin deaktiviert werden und werden nie auf dem Plugins-Bildschirm aufgeführt; das Entfernen von wp-smart-thumbnails entfernt sie nicht. Drittens erstellt es eine Magic-Login-URL unter /wp-login.php?_wplogin=, unterstützt durch ein zweites Must-Use-Plugin, class-wp-token-validate.php. Das Token lebt in der Option fz_emer_login_tokens, und das Plugin hakt init mit Priorität 1 ein, um es gegen ein Sitzungscookie einzutauschen. Dieses Token ist nicht an das versteckte Konto gebunden; es ist an den ältesten vorhandenen Administrator der Website gebunden, sodass jeder, der die URL besitzt, stillschweigend als der ursprüngliche Eigentümer angemeldet wird, in einer Sitzung, die für Protokolle, die nur eine Benutzer-ID aufzeichnen, nicht von einer echten zu unterscheiden ist. Beide Must-Use-Plugins werden verschleiert geschrieben, als XOR-plus-gzdeflate-Blobs mit zufälligen Variablennamen und einem frischen Schlüssel pro Website, sodass keine zwei infizierten Websites einen Hash teilen. Jedes wird dann rückdatiert: Das Skript durchsucht das WordPress-Stammverzeichnis, nimmt die älteste Änderungszeit, die es findet, und stempelt sie auf die gerade abgelegte Datei. Die Implantate sehen am Ende wie die ältesten Dateien des Systems aus und vereiteln die übliche Suche nach kürzlich geänderten Dateien.
Eine einzige erfolgreiche Ausführung des gespeicherten XSS hinterlässt dem Angreifer vier unabhängige Wege zurück in die Website, von denen nur einer vom WordPress-Dashboard aus sichtbar ist: der sichtbare Administrator, der über user-new.php mit vom C2 gelieferten Anmeldedaten erstellt wurde; der versteckte Administrator, der von emer-run.php erstellt und durch ein Must-Use-Plugin verborgen wird; die Magic-Login-URL, die den Inhaber als ältesten Administrator der Website authentifiziert; und der nicht authentifizierte Dateimanager im Plugin selbst, der per direkter Anfrage erreichbar ist. Das Entfernen des anfälligen Plugins oder sogar des bösartigen Plugins schließt keinen der letzten drei.
Gespeichertes XSS passt zu dieser Kampagne, weil es den schwierigsten Teil des Angriffs beseitigt: einen privilegierten Benutzer zur Mitarbeit zu bewegen. Ein reflektiertes XSS erfordert, dass das Opfer eine vom Angreifer kontrollierte URL besucht, während ein gespeichertes XSS bereits in der Anwendung steckt und in Daten sitzt, die Administratoren im Rahmen ihrer Arbeit öffnen: eine WooCommerce-Bestellung im ersten Fall, eine Ninja-Forms-Einreichung im zweiten. Es feuert in dem Moment, in dem sie hinschauen. Dieser Unterschied war für WordPress Core kürzlich von Bedeutung. Im September 2026 behob WordPress 7.1.1 ein nicht authentifiziertes gespeichertes XSS in wpautop(), das es vom Angreifer kontrolliertem Skript ermöglichte, durch Kommentarinhalte zu persistieren, vorbehaltlich der Kommentar-Freigabe. Das Angriffsmodell ist: Angreifer übermittelt Daten, WordPress speichert sie, Angreifer wartet, Administrator sieht sie an, Nutzlast läuft in wp-admin, dauerhafte Kompromittierung. Welches Plugin das anfängliche XSS liefert, spielt kaum eine Rolle; sobald JavaScript in einem authentifizierten administrativen Ursprung ausgeführt wird, ist die Post-Exploitation-Phase identisch, weshalb diese Angreifer gespeicherte XSS-Schwachstellen sammeln, anstatt für jedes Plugin eine separate Malware-Kette zu bauen.
Eine einzige Domain trägt jede Phase der Kampagne. Endpunkte auf imgcdn1.com umfassen /fz/x.js (browserbasiertes Post-Exploitation-Implantat), /fz/c.php?xa=check (Opferstatus und Aufgaben), /fz/c.php?xa=pkg (bösartiges Plugin-Paket), /fz/c.php?xa=admin_creds (vom Angreifer gewählte Administrator-Anmeldedaten) und /fz/c.php (Kompromittierungsmeldung). Die Domain wurde am 1. Oktober 2026 registriert, und ein öffentlicher DNS-Indizierungsdienst listet sie unter den Domains, die am 2. Oktober an den Cloudflare-Nameserver hazel.ns.cloudflare.com delegiert wurden. Patchstack sah sie zwei Tage später bei der Ausnutzung. Beide Schwachstellen waren am 22. September öffentlich bekannt gegeben worden, etwa zehn Tage bevor die Domain auftauchte; der Zeitpunkt passt zu einer Infrastruktur, die speziell für diese Kampagne aufgebaut wurde.
Zum Zeitpunkt der Veröffentlichung hat Patchstack diese Bereitstellungsinfrastruktur über mindestens zwei separate gespeicherte XSS-Schwachstellen bestätigt, und das Ausnutzungsvolumen bleibt in ihrer Telemetrie begrenzt. Keine der beiden Zahlen ist eine Obergrenze; die Post-Exploitation-Phase ist plugin-agnostisch, sodass jedes gespeicherte XSS, das JavaScript vor einen WordPress-Administrator bringt, ein Kandidatenvektor für dasselbe Implantat ist. Am 4. Oktober wurde CVE-2026-93836 von den IPs 204.8.96.109, 147.90.235.22 und 90.184.10.74 angegriffen. Am 5. Oktober wurde CVE-2026-94504 von 94.16.115.121 und 43.250.53.42 angegriffen. Die früheste Anfrage in Patchstacks Telemetrie wurde am 4. Oktober um 10:39 UTC beobachtet und zielte auf eine WooCommerce-Produkt-URL, wobei der Loader über den Parameter woosb_ids in einem URL-kodierten Wert mit einem Script-Tag geliefert wurde. Die Quell-IPs unterscheiden sich, während die Infrastruktur der zweiten Stufe und die Malware identisch bleiben, was mit einer Ausnutzung über mehrere Scan-Hosts hinter einer zentralisierten Nutzlast und einem C2-Server übereinstimmt. Vier der fünf Adressen sind Tor-Exit-Knoten, die Patchstacks Firewall zuvor blockiert hat; die fünfte, 43.250.53.42, ist für Spam- und Brute-Force-Aktivitäten markiert und erscheint in anderen aktuellen Kampagnen. Das Blockieren dieser Adressen ist allein keine dauerhafte Abschwächung. Die Zielpools unterscheiden sich stark: WPC Product Bundles hat mehr als 30.000 aktive Installationen, Ninja Forms mehr als 500.000.
Von Patchstack aufgeführte Malware-Indikatoren: Die analysierte x.js-Probe ist 19.378 Bytes groß; SHA-256 af803bc822cf9596b1f1785e1d59642f91f6fbc21f8e9943feefa19a6df8c2a4; MD5 8a4413c1aa058179ff54b95571bcf2a3. Die Must-Use-Plugins sind mit einem frischen Schlüssel pro Website verschleiert und werden keinen festen Hash ergeben, daher werden sie nach Pfad aufgeführt: /wp-content/mu-plugins/class-wp-query- und /wp-content/mu-plugins/class-wp-token-validate.php. Die Nutzlast ist https://imgcdn1.com/fz/x.js, C2 ist https://imgcdn1.com/fz/c.php, und der bösartige Plugin-Slug ist wp-smart-thumbnails. Website-Betreiber sollten nach diesen Indikatoren suchen und auch nach versteckten Administratorkonten prüfen, da die sichtbare Benutzerliste möglicherweise nicht das vollständige Bild zeigt.
Für Website-Betreiber, die nicht rund um die Uhr jede Plugin-Empfehlung überwachen können, kann ein verwalteter WordPress-Host wie AEU Hosting automatische Backups und WordPress-spezifische Sicherheitshärtung bieten, um die Wahrscheinlichkeit zu verringern, dass ein verpasstes Update zu einem versteckten Admin-Konto führt. Patchstack überwacht weiterhin die Ausnutzungsaktivität und die Entwicklung der Nutzlast auf Änderungen in Infrastruktur, Verschleierung und Post-Exploitation-Techniken und wird seinen Bericht aktualisieren, sobald weitere betroffene Plugins bestätigt werden. Die Kampagne ist eine Erinnerung daran, dass Patchen nicht nur das anfällige Plugin betrifft, da die Persistenzschicht des Angreifers die Plugin-Entfernung überlebt.