Selbstheilende WordPress-Malware versteckt sich in Datenbank und RAM
Sicherheitsanalysten von Sucuri haben eine WordPress-Malware-Familie dokumentiert, die sie SC nennen – ein selbstheilendes Netz, das eine Entfernung überlebt, indem es Kopien von sich selbst an mindestens acht Orten gleichzeitig speichert und jede gelöschte Komponente innerhalb von Sekunden wiederherstellt. Die am 30. September 2026 von Sucuri-Sicherheitsanalyst Gabriel Barbosa veröffentlichte Forschung stammt aus einer echten Bereinigung, bei der dieselbe Backdoor immer wieder zurückkehrte, egal wie sorgfältig sichtbare Dateien gelöscht wurden. Der Name SC stammt von den 'SC_'-Markierungen, die im eingeschleusten Code gefunden wurden.
Laut Sucuri teilen alle wiederhergestellten SC-Dateien dasselbe Verschleierungsschema: Es gibt kein eval, keine Markierung auf den neuesten Teilen und keine lesbaren Funktionsnamen. Stattdessen trägt jede Datei eine Tabelle mit verschlüsselten Zeichenfolgen und einen kleinen Decoder, der einen numerischen Index durch eine positionale Substitutions-Chiffre in einen echten Funktionsnamen auflöst.
Die Infektion hat acht Kernkomponenten. Die erste ist ein .user.ini-Trigger mit einer einzigen Zeile, die auto_prepend_file setzt – eine PHP-Konfigurationsanweisung, die eine bestimmte Datei vor jeder Anfrage in diesem Verzeichnisbaum ausführt, selbst bei Anfragen, die WordPress nie erreichen. PHP speichert diesen Wert im Cache, weshalb das Löschen des Prepend-Ziels bei noch warmem Cache dazu führt, dass jede PHP-Anfrage auf dem Konto fehlschlägt, bis der Cache abläuft.
Die zweite Komponente ist eine sichtbare Shim-PHP-Datei. Im dokumentierten Fall hieß sie c1b12371.php, aber der Name variiert von Website zu Website. Die .user.ini zeigt auf diesen Shim, und der Shim tut nur eines: Wenn eine versteckte Datei mit Punktpräfix daneben existiert, bindet er diese versteckte Datei ein. Wenn ein Verteidiger nur die versteckte Datei entfernt, tut der Shim still nichts und die Website bleibt online, was dem Angreifer Zeit verschafft, während eine andere Komponente die versteckte Datei neu erstellt.
Die dritte Komponente ist die versteckte Datei mit Punktpräfix, der erste echte Loader. Sie lokalisiert das gefälschte Plugin und baut es im mu-plugins-Verzeichnis aus drei Quellen wieder auf, die in dieser Reihenfolge versucht werden: eine vorhandene Kopie im plugins-Ordner, ein codierter Stub im Cache-Verzeichnis und ein ZIP-Wiederherstellungsbundle mit zufälligem Hex-Namen. Sie schreibt über eine temporäre Datei, setzt die Dateiberechtigungen auf 0644 und ruft opcache_invalidate auf, damit die frisch geschriebene Datei sofort ausgeführt wird. Sie definiert außerdem eine Konstante namens SC_AUTO_PREPEND, die sie mit der auto_prepend-Seite der Familie verbindet.
Die vierte Komponente ist das wp-content/db.php-Drop-in, eine spezielle WordPress-Datei, die sehr früh beim Start geladen wird. Diese Kopie trägt die gesamte Backdoor-Nutzlast als gzip- und base64-Blob in sich – zwei gängige Komprimierungs- und Kodierungsformate. Bei jeder Anfrage, bei der das gefälschte Plugin fehlt oder zu klein ist, dekodiert sie den Blob und schreibt das Plugin direkt auf die Festplatte zurück.
Die fünfte Komponente ist das wp-content/advanced-cache.php-Drop-in, die früheste und gefährlichste Position von allen. Wenn Caching aktiviert ist, lädt WordPress advanced-cache.php vor normalen Plugins. Im Gegensatz zu db.php trägt es die Nutzlast nicht inline. Es ist ein Finder, der das Plugin aus fünf unabhängigen Quellen in dieser Reihenfolge wiederherstellen kann: ein vorhandenes mu-Plugin, eine vorhandene Plugin-Kopie, ein System-V-Shared-Memory-Segment mit PHP-Code, ein ZIP-Bundle, das in mehreren Ordnern gesucht wird, und schließlich die Datenbank selbst. Für den Datenbankpfad öffnet es eine direkte Verbindung mit den eigenen Zugangsdaten-Konstanten der Website und liest die Nutzlast aus einer bestimmten Optionszeile, wobei es dasselbe gzip-Format dekodiert. Sobald es eine Kopie hat, hängt es sich an plugins_loaded und bindet sie ein.
Die sechste Komponente ist eine Theme-Injektion. Der Angreifer hat einen begrenzten Block an das Ende der functions.php des aktiven Themes angehängt, eingefasst von Begin- und End-Markierungen. Dieser Block ist der theme-residente Zwilling von db.php: Er schreibt das Plugin neu, wann immer es fehlt.
Die siebte und achte Komponente sind zwei identische Kopien der eigentlichen Backdoor-Nutzlast, installiert sowohl als Must-Use-Plugin (das automatisch und unsichtbar geladen wird) als auch als normales Plugin. Der Plugin-Ordner enthält sogar eine überzeugende gefälschte Einstellungsseite, einen Shortcode und einen Aktivierungs-Hook in aller Öffentlichkeit, sodass ein kurzer Blick ein echtes Caching-Plugin vermuten lässt. Die beiden Kopien sind absichtlich redundant, und die Nutzlast aktualisiert wettbewerbsfähig eine von der anderen, damit beide auf derselben Version bleiben.
Die Nutzlast ist der Grund, warum der Rest des Netzes existiert. Einmal ausgeführt, erfüllt sie mehrere unterschiedliche Aufgaben. Sie versteckt sich selbst, indem sie die Plugin-Liste, den Update-Transienten und die Site- und Netzwerk-Plugin-Ansichten filtert, um ihren eigenen Eintrag zu entfernen, sodass sie weder im Admin-Plugin-Bildschirm noch bei Update-Prüfungen erscheint. Sie gibt außerdem Admin-JavaScript aus, um sich als Fallback aus der Plugin-Tabelle zu entfernen.
Für Befehl und Kontrolle kommuniziert die Nutzlast über Blockchain-Infrastruktur. Sie trägt eine Liste von etwa zwanzig öffentlichen Ethereum-RPC-Gateways und eine Reihe von Smart-Contract-Methodenselektoren. Anstatt eines einzelnen fest codierten Servers sendet sie Anfragen an diese legitimen Drittanbieter-Gateways, um Anweisungen aus einem Smart Contract zu lesen. Da diese Gateways legitim sind, bleiben beim Blockieren nur des im Datenverkehr gesehenen die übrigen als Fallbacks, sodass die gesamte Menge zusammen blockiert werden muss.
Die Nutzlast erstellt einen Fingerabdruck der Website und holt eine Nutzlast. Sie sammelt die Website-URL und den Host, WordPress- und Plugin-Versionen, Pfad-Hashes, aktive Themes, die mu-Plugin-Liste und aktuelle Administrator-Sitzungstokens, verschlüsselt dieses Bündel und sendet es an den aufgelösten Endpunkt. Die Antwort kann Front-End-JavaScript zum Injizieren enthalten, das in einem Online-Shop Checkout-Skimming ermöglicht, sowie neues PHP zum Installieren und Listen von Sicherheitsplugins, die deaktiviert und gelöscht werden sollen. Wenn sie angewiesen wird, ein Sicherheitsplugin zu entfernen, kann sie es deaktivieren, sein Verzeichnis löschen und sogar zuerst ein anderes Konto neu zuweisen oder hochstufen.
Die Nutzlast erstellt außerdem einen versteckten Administrator. Sie übernimmt entweder einen vorhandenen versteckten Admin oder generiert einen neuen und schreibt das Konto direkt in die users- und usermeta-Tabellen, wenn die normale WordPress-API nicht verfügbar ist. Sie speichert die Fähigkeiten unter dem Meta-Schlüssel default capabilities und versteckt das Konto dann durch Abfrage- und Zählfilter aus der Benutzerliste, den Benutzerzahlen und den Rollenansichten. Sie fälscht außerdem gültige Authentifizierungs-Cookies für dieses Konto, sodass sich der Betreiber ohne Passwort anmelden kann.
Die Nutzlast stellt einen Live-Beacon bereit. Ein magischer Anfrageparameter in Form eines kurzen Präfixes gefolgt von einem festen Wert wird behandelt, bevor WordPress vollständig geladen ist. Solange das Netz vorhanden ist, gibt diese Anfrage eine normale Antwort mit Inhalt zurück und beendet sich dann.
Schließlich baut die Nutzlast das gesamte Netz wieder auf. Sie hängt sich an eine große Menge von WordPress-Aktionen und -Filtern, deren einziger Zweck es ist, jede andere Komponente wieder auszuschreiben. Sie regeneriert die db.php- und advanced-cache.php-Drop-ins, die Theme-Injektion, den versteckten Loader und seine .htaccess- und .user.ini-Prepend-Anweisungen, das ZIP-Wiederherstellungsbundle, das Shared-Memory-Segment und die Datenbankkopie der Nutzlast. Sie öffnet sogar eine rohe Datenbankverbindung, um ihre Nutzlast-Option direkt einzufügen und WordPress zu umgehen.
Die wichtigste Lehre aus diesem Fall ist, dass Persistenz nicht auf Dateien beschränkt ist. Sucuri hat lebende Kopien der Nutzlast an drei Nicht-Datei-Orten wiederhergestellt, von denen jeder das gesamte Set bei der nächsten Anfrage wieder aufbaut. Die Datenbank speichert die vollständige Nutzlast in einer Optionszeile unter einem zufälligen Namen im selben gzip- und base64-Format. Das advanced-cache.php-Drop-in liest sie über eine direkte Datenbankverbindung zurück. Deshalb schlägt eine vollständige und korrekte Dateibereinigung fehl: Der nächste Seitenaufruf stellt alles aus der Zeile wieder her. Auf Servern, die System-V-Shared-Memory unterstützen – eine Methode für Prozesse, Daten im RAM zu teilen –, wird die Nutzlast in ein Segment geschrieben, das durch einen festen numerischen Schlüssel identifiziert wird. Dieses Segment lebt im RAM, überlebt also sowohl Dateilöschung als auch Datenbankbereinigung, und auf Shared Hosting kann es sogar einem anderen Konto gehören. Die Infektion registriert außerdem Cron-Hooks, darunter zufällige Namen neben einem bekannten Abruf-Hook. System-Cron führt die WordPress-Cron-Datei aus, nicht der Besucherverkehr, und löst dann die Neubereitstellung nach Zeitplan aus. Daneben sah Sucuri bei verwandten SC-Varianten Datenbank-Trigger, die beim Einfügen einen Administrator neu erstellen. Ein Trigger läuft innerhalb der Datenbank, überlebt also eine vollständige Dateiwiederherstellung und sogar das Löschen des Kontos, das er immer wieder neu erstellt.
Von Sucuri aufgeführte Kompromittierungsindikatoren umfassen unerwartete PHP-Blöcke in wp-content/db.php oder wp-content/advanced-cache.php, die mit einer SC_-artigen Begin-Markierung und einer Schutz-Konstante beginnen; einen begrenzten Block am Ende der functions.php des aktiven Themes, eingefasst von Begin- und End-Markierungen, manchmal mit doppelter Begin-Markierung; eine .user.ini, php.ini oder .htaccess mit einer auto_prepend_file-Anweisung, die auf eine versteckte PHP-Datei mit Punktpräfix zeigt; ein gefälschtes Plugin, das sowohl in wp-content/mu-plugins als auch in wp-content/plugins mit übereinstimmendem Inhalt und einer plausiblen Einstellungsseite vorhanden ist; ein ZIP-Wiederherstellungsbundle mit zufälligem Hex-Namen in wp-content, wp-content/uploads oder einem Theme-Ordner; eine Optionszeile mit zufälligem Namen, die einen großen gzip- und base64-Blob sowie Steueroptionen und Transienten mit einem sc_-artigen Präfix enthält; ein Shared-Memory-Segment mit lesbarem PHP, das mit einem öffnenden Tag beginnt; ein voll privilegierter Administrator, der möglicherweise nicht in der Benutzerliste erscheint, mit Fähigkeiten, die unter dem Meta-Schlüssel default capabilities gespeichert sind, und manchmal eine verwaiste Option, die auf die ID dieses Kontos zeigt und nach einer teilweisen Bereinigung zurückbleibt; sowie ausgehende Anfragen an öffentliche Ethereum-RPC-Gateways vom Webserver.
Sucuris Bereinigungsanleitung betont, dass die Reihenfolge der Operationen wichtiger ist als einzelne Löschungen. Dateien zuerst in der falschen Reihenfolge zu entfernen, löst einfach ein Neuschreiben aus. Der funktionierende Ansatz besteht darin, die Ausführung zu unterbinden, die Off-Disk-Kopien vor den On-Disk-Kopien zu löschen und erst dann Dateien in einem einzigen Durchgang zu entfernen. Zuerst das Prepend neutralisieren, bevor sein Ziel gelöscht wird. Da auto_prepend_file von PHP bis zu 300 Sekunden zwischengespeichert wird, leeren Sie zuerst das Prepend-Ziel zu einem inerten Stub und entfernen Sie dann die Anweisung aus .user.ini, php.ini und .htaccess. Das Löschen des Ziels bei noch warmem Cache legt jede PHP-Anfrage auf dem Konto lahm. Zweitens die Off-Disk-Nutzlastkopien löschen. Entfernen Sie die Nutzlastzeile aus der options-Tabelle, leeren Sie das Shared-Memory-Segment und löschen Sie die Steueroptionen und Transienten. Wenn eine davon übrig bleibt, schreibt die nächste Anfrage über advanced-cache.php das gesamte Set auf die Festplatte zurück. Auf Shared Hosting kann ein Shared-Memory-Segment einem anderen Konto gehören; in diesem Fall kann nur dieses Konto oder der Host es entfernen, und es wird harmlos, sobald die Drop-ins, die es lesen, entfernt sind. Drittens die geplanten Aufgaben und alle Datenbank-Trigger entfernen. Löschen Sie die bösartigen Cron-Hooks, damit System-Cron nicht nach Zeitplan neu bereitstellen kann, und überprüfen Sie information_schema.TRIGGERS auf jeden Trigger, der beim Einfügen einen Administrator neu erstellt. Ein überlebender Trigger baut den Zugriff sogar nach einer vollständigen Dateiwiederherstellung wieder auf. Viertens den versteckten Administrator entfernen. Löschen Sie das Konto, dessen Fähigkeiten unter dem Meta-Schlüssel default capabilities gespeichert sind, und bereinigen Sie die verwaiste Option, die auf seine ID zeigt. Fünftens die Dateien in einem Durchgang bereinigen. Entfernen Sie die eigenständigen Loader und den Shim, löschen Sie beide Kopien des gefälschten Plugins aus den mu-plugins- und plugins-Ordnern, löschen Sie das ZIP-Wiederherstellungsbundle, wo immer es versteckt war, und entfernen Sie die injizierten Drop-ins. Für db.php und advanced-cache.php bedeutet dies, die bösartigen Dateien zu löschen. Für die functions.php des Themes bedeutet es, nur den begrenzten Block zwischen den Begin- und End-Markierungen zu entfernen, damit der legitime Theme-Code intakt bleibt. Sechstens erneut scannen und auf neu erstellte Dateien achten. Führen Sie einen vollständigen Scan durch und überwachen Sie dann die betroffenen Pfade. Eine zurückkehrende Komponente bedeutet, dass ein Persistenzpunkt überlebt hat oder der ursprüngliche Einstiegspfad noch offen ist.
Sucuris Präventionsratschläge beginnen damit, alles gepatcht zu halten. Die meisten Kompromittierungen, die sie behandeln, nutzen bekannte, bereits behobene Schwachstellen in veralteten Komponenten aus, und zeitnahe Updates verkürzen das Zeitfenster des Angreifers. Verwenden Sie eine Web Application Firewall, die Exploit-Versuche blockieren kann, bevor sie die Anwendung erreichen, den Beacon-Parameter abfängt und hilft, ausgehende Anfragen an den Befehlskanal zu stoppen. Überprüfen Sie regelmäßig die Orte, an denen sich diese Familie versteckt: die options-Tabelle, geplante Aufgaben, Datenbank-Trigger und Benutzerkonten. Behandeln Sie jedes Wiederauftauchen als unvollständige Bereinigung. Wenn eine Datei zurückkehrt, lebt noch eine Kopie der Nutzlast irgendwo außerhalb der Festplatte oder eine geplante Aufgabe ist noch scharf; gehen Sie also zu den Off-Disk-Quellen zurück, anstatt dieselbe Datei erneut zu löschen. Website-Besitzer können die Auswirkungen solcher tiefen Reinfektionen auch verringern, indem sie verwaltetes WordPress-Hosting wie AEU Hosting nutzen, das automatische Backups, Sicherheitshärtung und Expertenunterstützung bietet, um eine saubere, überwachte Umgebung zu gewährleisten.
SC ist eine Erinnerung daran, dass eine moderne WordPress-Infektion ein System und keine Datei sein kann. Dieses Toolkit verteilt identische Kopien einer Backdoor über Drop-ins, das Theme, ein gefälschtes Plugin an zwei Orten, die Datenbank und den gemeinsamen Speicher, versteckt seinen Befehlskanal in legitimer Blockchain-Infrastruktur und schreibt sich bei der nächsten Anfrage aus jeder überlebenden Kopie selbst neu. Eine dauerhafte Lösung behandelt die Dateien, die Datenbank und den gemeinsamen Speicher als ein Problem, deaktiviert die Ausführung vor dem Löschen, entfernt Persistenz in jeder Form, die sie annimmt, schließt den ursprünglichen Einstiegspunkt und rotiert alle Zugangsdaten, die der Angreifer berührt haben könnte.