Joomla nach einem Webshell-Hack: Welche Passwörter und Sitzungen sollte man ändern?

Nach einem bestätigten Webshell-Befall reicht es nicht, die schädlichen PHP-Dateien zu löschen und die betroffene Joomla-Erweiterung zu aktualisieren.

Wenn fremder PHP-Code mit den Rechten des Webservers ausgeführt werden konnte, muss man davon ausgehen, dass dieser Code auch auf Dateien zugreifen konnte, die für den Webserver lesbar waren.

Bei Joomla gehört dazu insbesondere die configuration.php.

Damit können nach einem solchen Vorfall verschiedene Zugangsdaten als potentiell offengelegt gelten.

Dieser Beitrag beschreibt, welche Zugangsdaten ich nach einem tatsächlichen Joomla-Webshell-Befall geändert habe – und in welcher Reihenfolge.

Ausgangslage

In meinem Fall waren über eine verwundbare Joomla-Erweiterung PHP-Webshells in den Webspace gelangt.

Damit war bestätigt:

Fremder PHP-Code konnte mit den Rechten des Webspace-Benutzers ausgeführt werden.

Das bedeutet noch nicht automatisch, dass der Server als root kompromittiert wurde.

Aber alles, was der Webspace-Benutzer lesen konnte, musste als potentiell bekannt betrachtet werden.

Dazu gehörte insbesondere:

configuration.php

In dieser Datei stehen unter anderem die Joomla-Datenbankverbindung und weitere Konfigurationswerte.

Erst bereinigen, dann Passwörter ändern

Bevor Zugangsdaten rotiert werden, sollte der offensichtliche Angriffsweg geschlossen sein.

Sonst besteht die Gefahr, dass ein weiterhin vorhandener Webshell die neuen Zugangsdaten einfach erneut ausliest.

Die Reihenfolge war deshalb grundsätzlich:

  1. verwundbare Erweiterung aktualisieren bzw. Angriffsweg blockieren,
  2. bekannte Webshells und Backdoors sichern und aus dem Webroot entfernen,
  3. nach weiteren verdächtigen Dateien und Persistenz suchen,
  4. erst danach Zugangsdaten rotieren.

Das bedeutet nicht, dass damit garantiert jede mögliche Hintertür ausgeschlossen ist. Aber neue Zugangsdaten in ein offensichtlich noch kompromittiertes System einzutragen wäre wenig sinnvoll.

1. Joomla-Administratorpasswörter ändern

Zunächst wurden die Passwörter aller aktiven Joomla-Administratoraccounts geändert.

Dabei sollte man nicht nur den Hauptadministrator berücksichtigen.

Im Joomla-Backend lohnt sich die Prüfung:

Benutzer → Verwalten

und dort insbesondere:

Nicht mehr benötigte privilegierte Konten sollten deaktiviert oder entfernt werden.

Wichtig ist außerdem:

Das Passwort sollte neu sein und nicht lediglich eine Variante des bisherigen Passworts.

Wenn Zugangsdaten möglicherweise abgeflossen sind, sollte das alte Passwort auch bei anderen Diensten nicht mehr verwendet werden.

2. Bestehende Joomla-Sitzungen beenden

Ein neues Passwort beendet nicht zwangsläufig jede bereits bestehende Sitzung.

Ein Angreifer könnte theoretisch noch über eine gültige Session verfügen.

Deshalb habe ich zusätzlich die Joomla-Sitzungstabelle geleert.

Der Tabellenname hängt vom Präfix der jeweiligen Joomla-Installation ab und kann beispielsweise so aussehen:

abc_session

Vorher sollte man natürlich prüfen, welche Tabelle tatsächlich zur Installation gehört.

Das Leeren der Session-Tabelle meldet alle aktuell angemeldeten Benutzer ab.

Danach müssen sich auch legitime Administratoren erneut anmelden.

Je nach Joomla-Version und verwendeten Funktionen können außerdem persistente Login-Schlüssel existieren. Auch diese sollten nach einem relevanten Sicherheitsvorfall geprüft bzw. invalidiert werden.

3. Datenbankpasswort rotieren

Dieser Schritt ist besonders wichtig, weil Joomla seine Datenbankzugangsdaten normalerweise in:

configuration.php

speichert.

Wer diese Datei über eine Webshell lesen konnte, konnte damit unter Umständen auch Benutzername und Passwort der Joomla-Datenbank erfahren.

Das Datenbankpasswort sollte deshalb geändert werden.

Dabei gibt es allerdings eine kleine Falle:

Datenbankserver und Joomla müssen anschließend dasselbe neue Passwort kennen.

Ändert man nur das Passwort des MySQL-/MariaDB-Benutzers, kann Joomla keine Datenbankverbindung mehr herstellen.

Ändert man nur configuration.php, gilt dasselbe.

Sinnvolle Reihenfolge beim DB-Passwort

Vorher unbedingt ein Backup der Joomla-Konfiguration anlegen.

Zum Beispiel:

cp -a configuration.php /root/configuration.php-before-db-password-change

Dabei ist zu beachten:

Diese Sicherung enthält anschließend das alte Datenbankpasswort im Klartext.

Sie sollte deshalb:

Dann:

  1. neues Datenbankpasswort erzeugen,
  2. Passwort des Datenbankbenutzers ändern,
  3. Joomla-configuration.php unmittelbar auf dasselbe Passwort setzen,
  4. Datenbankverbindung testen,
  5. Webseite testen,
  6. Joomla-Backend testen.

Während dieses kurzen Übergangs kann die Webseite vorübergehend einen HTTP-500-Fehler liefern, wenn Datenbank und Joomla-Konfiguration noch nicht synchron sind.

Das allein ist in diesem Moment noch kein Hinweis auf einen neuen Defekt.

Datenbankverbindung direkt testen

Nach der Änderung sollte nicht nur die Webseite getestet werden.

Sinnvoll ist auch ein direkter Verbindungstest mit PHP oder dem MySQL-/MariaDB-Client.

Bei PHP kann beispielsweise ein sehr kleiner Test verwendet werden, ohne das Passwort in der Shell-History zu hinterlassen.

Wichtig ist vor allem:

Verbindung erfolgreich

und anschließend ein normaler Aufruf der Joomla-Seite.

Bei meinem System wurden danach sowohl Startseite als auch Administratorbereich erneut kontrolliert.

Beide mussten wieder HTTP 200 liefern.

4. Passwort des Webspace-/Hosting-Benutzers ändern

Wenn ein Angreifer Code mit den Rechten des Webspace-Benutzers ausführen konnte, ist auch dessen Zugang relevant.

Bei Plesk gibt es dafür typischerweise einen Systembenutzer für die jeweilige Subscription bzw. Domain.

Dieser Benutzer kann je nach Konfiguration beispielsweise für:

verwendet werden.

Auch dessen Passwort wurde deshalb geändert.

Selbst wenn keine erfolgreiche SSH-Anmeldung dieses Benutzers nachgewiesen wurde, ist die Rotation sinnvoll, wenn dessen Zugangsdaten irgendwo für den kompromittierten Prozess erreichbar gewesen sein könnten.

5. Private SSH-Schlüssel prüfen

Ein Punkt, den man leicht übersieht:

Im Home-Verzeichnis des Webspace-Benutzers können private SSH-Schlüssel liegen.

Beispielsweise:

~/.ssh/id_rsa

In meinem Fall existierte dort tatsächlich ein privater RSA-Schlüssel ohne Passphrase.

Da der Webshell mit den Rechten dieses Benutzers lief, musste angenommen werden, dass der Schlüssel ausgelesen worden sein könnte.

Der Schlüssel wurde deshalb nicht weiter verwendet.

Bei einem kompromittierten privaten SSH-Schlüssel gilt:

Nicht nur die Datei löschen oder verschieben, sondern auch prüfen, wo der zugehörige öffentliche Schlüssel als authorized_key hinterlegt wurde.

Dort sollte der alte Schlüssel entfernt und gegebenenfalls durch einen neuen ersetzt werden.

6. Muss das Root-Passwort ebenfalls geändert werden?

Nicht zwangsläufig aufgrund der Webshell allein.

Hier ist die Unterscheidung wichtig.

Eine PHP-Webshell beweist zunächst die Kompromittierung des PHP-/Webspace-Kontexts.

Sie beweist nicht automatisch:

root wurde kompromittiert

Das Root-Passwort sollte natürlich geändert werden, wenn es Hinweise gibt auf:

In meinem Fall wurde das Root-Passwort im Zuge der Sicherheitsarbeiten ebenfalls erneuert.

Für die Bewertung des Vorfalls blieb die Formulierung trotzdem:

Webspace-Kompromittierung bestätigt, Root-Kompromittierung nicht nachgewiesen.

Diese Unterscheidung hilft, Beobachtungen und Vermutungen nicht miteinander zu vermischen.

7. Plesk- und Provider-Zugang nicht vergessen

Je nach Hostingumgebung können außerdem weitere Zugangsdaten relevant sein:

Plesk
Hosting-Provider
DNS-Provider
Domain-Registrar
Backup-System
Deployment-Dienste
Git-Zugänge

Ob sie tatsächlich geändert werden müssen, hängt davon ab, ob die entsprechenden Zugangsdaten für das kompromittierte System erreichbar waren.

Ein im Browser gespeichertes Provider-Passwort ist beispielsweise durch eine PHP-Webshell auf dem Server nicht automatisch kompromittiert.

Ein API-Key in einer für den Webserver lesbaren Konfigurationsdatei dagegen schon.

Die bessere Frage lautet also:

Konnte der kompromittierte Benutzer dieses Geheimnis lesen?

8. Auch Mail-Zugangsdaten und API-Keys berücksichtigen

Viele Joomla-Installationen enthalten mehr Geheimnisse als nur die Datenbankverbindung.

Mögliche Beispiele:

SMTP-Passwörter
API-Keys
Cloud-Zugangsdaten
Backup-Credentials
OAuth-Secrets
externe Datenbankzugänge
FTP-/SFTP-Zugangsdaten

Sie können in:

configuration.php
.php-Dateien
.env-Dateien
Backup-Dateien
Erweiterungskonfigurationen

liegen.

Nach einer Webshell-Kompromittierung lohnt sich deshalb die Suche nach weiteren Secrets im Webroot.

Nicht jedes gefundene Passwort muss automatisch geändert werden.

Aber alles, was der kompromittierte Benutzer lesen konnte und noch gültig ist, sollte bewertet werden.

9. Vorsicht mit alten Backups

Während einer Reparatur entstehen schnell Dateien wie:

configuration.php.bak
configuration.php.old
configuration.php-before-change

Diese Backups enthalten häufig dieselben Passwörter wie das Original.

Noch problematischer wird es, wenn solche Dateien versehentlich im öffentlichen Webroot liegen.

Deshalb:

Ein Passwortwechsel hilft wenig, wenn anschließend zehn alte Konfigurationsbackups mit dem vorherigen Passwort herumliegen.

10. Nach jeder Änderung testen

Bei mehreren gleichzeitigen Passwortänderungen kann es sonst schwierig werden herauszufinden, welcher Schritt eine Anwendung beschädigt hat.

Deshalb habe ich die Änderungen nacheinander durchgeführt und jeweils getestet.

Typische Tests:

curl -I https://example.org/

Erwartet:

HTTP 200

Zusätzlich:

Frontend aufrufen
Joomla-Backend aufrufen
Administrator-Login testen
Datenbankzugriff prüfen

So lässt sich ein Fehler unmittelbar dem letzten Änderungsschritt zuordnen.

11. Neue Zugangsdaten nicht in der Shell-History hinterlassen

Gerade bei der Arbeit als root sollte man vermeiden, Passwörter direkt in Befehle einzutragen wie:

mysql -u user -pSUPERGEHEIMESPASSWORT

Denn je nach Shell und Konfiguration kann dieser Befehl in der History landen.

Besser ist:

mysql -u user -p

Danach fragt der Client das Passwort interaktiv ab.

Dasselbe Prinzip gilt für andere Programme, sofern sie eine sichere Passwortabfrage anbieten.

12. Reihenfolge aus der Praxis

Nach dem konkreten Vorfall hat sich für mich folgende Reihenfolge als sinnvoll erwiesen:

  1. Sicherheitslücke schließen.
  2. bekannte Webshells und Backdoors entfernen bzw. quarantänisieren.
  3. nach weiterer Persistenz suchen.
  4. Joomla-Administratorpasswörter ändern.
  5. Joomla-Sessions invalidieren.
  6. Datenbankpasswort ändern und configuration.php synchron aktualisieren.
  7. Datenbank und Webseite testen.
  8. Passwort des Webspace-/Hosting-Benutzers ändern.
  9. vorhandene private SSH-Schlüssel bewerten und gegebenenfalls ersetzen.
  10. weitere für den Webserver lesbare Secrets prüfen.
  11. Plesk-, Provider- und DNS-Zugänge nach Risikolage bewerten.
  12. alte Backups mit inzwischen ungültigen oder sensiblen Zugangsdaten aufräumen.
  13. anschließend erneut Logs, Prozesse und Dateisystem kontrollieren.

Was ein Passwortwechsel nicht leistet

Eine Credential-Rotation ist wichtig.

Sie beseitigt aber keine Malware.

Wenn weiterhin eine Webshell aktiv ist, können neue Passwörter möglicherweise sofort wieder abgegriffen werden.

Umgekehrt bedeutet eine erfolgreiche Bereinigung des Webroots nicht, dass alte Zugangsdaten weiterhin bedenkenlos verwendet werden sollten.

Beides gehört zusammen:

Bereinigung + Zugangsdatenrotation

Kurzfassung

Nach einem bestätigten Joomla-Webshell-Befall würde ich mindestens folgende Dinge prüfen bzw. erneuern:

Joomla-Administratorpasswörter
Joomla-Sitzungen
Datenbankpasswort
Webspace-/Hosting-Benutzer
private SSH-Schlüssel
SMTP-/API-/sonstige Secrets

Weitere Administrationszugänge wie:

root
Plesk
Hosting-Provider
DNS
Domain-Registrar

sollten abhängig davon bewertet werden, ob es einen realistischen Zugriffspfad oder konkrete Hinweise auf eine Kompromittierung gibt.

Die wichtigste Grundregel lautet:

Alles, was ein kompromittierter Webspace-Benutzer lesen konnte, sollte als potentiell offengelegt betrachtet werden.

Und genauso wichtig:

Eine PHP-Webshell beweist nicht automatisch eine Root-Kompromittierung.

Diese beiden Aussagen helfen, nach einem Vorfall weder zu wenig noch unnötig viel aus den vorhandenen Spuren abzuleiten.