Fortgeschrittene PrestaShop-Härtung für Shops, die noch nicht aktualisiert werden können
In unserer forensischen Analyse eines Magecart-Angriffs haben wir einen Punkt gemacht, der im Nachhinein einen eigenen Artikel verdient: Schadcode von einem Shop zu entfernen ist nicht dasselbe, wie den Shop zu reparieren. Wir entfernten den Skimmer, die Web-Shells und die SUID-Root-Binaries aus jenem PrestaShop-1.7.x-Shop – und kurz darauf wurde er erneut getroffen. Nicht über eine übersehene Hintertür, sondern durch die Vordertür: eine Schwachstelle auf Anwendungsebene, die die Bereinigung eingedämmt, aber nie geschlossen hatte. Dieser Beitrag ist das Playbook, das wir beim ersten Mal hätten anwenden sollen – wie man einen PrestaShop-Shop härtet, den man noch nicht aktualisieren kann, sodass das Entfernen der Nutzlast auch die Lücke schließt, durch die sie kam.
Wenn Sie heute auf PrestaShop 8 oder 9 aktualisieren können, tun Sie das – es ist die einzige dauerhafte Lösung, und der Rest dieses Artikels ist ein Notbehelf. Für einen nicht-trivialen Shop ist ein Upgrade aber ein Projekt über mehrere Wochen (Modulkompatibilität, Theme-Refactoring, Neuverdrahtung der Zahlungsmodule). Die Übergangszeit ist real, und während ihr sind Sie ein Ziel. So überstehen Sie sie. Dies ist die fortgeschrittene Ergänzung zu unserer PrestaShop-Härtungs-Checkliste; beginnen Sie dort mit den Grundlagen, kommen Sie hierher für die Vorfalls-Ebene.
1. Finden Sie den Eintrittsvektor, nicht nur die Nutzlast
Der teuerste Fehler in der Vorfallsreaktion ist es, das sichtbare Symptom für die Wunde zu halten. Ein Skimmer im Theme-JavaScript ist das Symptom. Die Wunde ist das, was es einem Angreifer überhaupt erlaubt hat, dieses JavaScript zu schreiben – eine Web-Shell, ein ungepatchtes Modul, ein Injection-Endpunkt. Entfernen Sie den Skimmer und lassen die Wunde offen, haben Sie sich Tage erkauft, keine Sicherheit.
Bevor Sie irgendetwas härten, beantworten Sie eine Frage mit Belegen: Wie gelangte Code auf die Festplatte? Lesen Sie die Zugriffsprotokolle rund um die Datei-Erstellungszeitstempel des Schadcodes (verwenden Sie ctime, nicht mtime – Angreifer fälschen mtime). Korrelieren Sie verdächtige POST-Muster, ungewöhnliche Query-Parameter und Anomalien in der Antwortgröße mit dem Moment, in dem die Nutzlast auftauchte. Wenn Sie den Eintrittsvektor nicht benennen können, gehen Sie davon aus, dass er noch offen ist.
2. Virtuelles Patchen der bekannten 1.7.x-Angriffskette vor Ort
PrestaShop 1.7.x hat eine Handvoll gut bekannter, waffenfähiger Schwachstellen, die automatisierte Scanner verketten. Wenn Sie nicht aktualisieren können, patchen Sie die konkreten Code-Pfade direkt. Das sind Notbehelfe – verfolgen Sie die offiziellen Hinweise – aber sie schließen die Türen, die aktiv eingetreten werden.
2.1 SQL-Injection in der Facettensuche
Ältere ps_facetedsearch-Builds verketten Filterwerte direkt in SQL. Das ist ein Blind-SQL-Injection-Primitiv und auf einem 1.7.x-Shop oft der eigentliche Eintrittspunkt. Escapen und casten Sie jeden aus der Anfrage stammenden Wert:
// BEFORE (vulnerable): raw value concatenated into the WHERE clause
$conditions[] = $alias.'.'.$field.$operator.current($values);
// AFTER: string values escaped, numeric ranges cast
$conditions[] = $alias.'.'.$field.$operator."'".pSQL(current($values))."'";
$orConditions[] = $alias.'.'.$field.$operator.(float) $value;
2.2 Die Smarty-MySQL-Cache-RCE (CVE-2022-36408)
Das ist die Hälfte der Kette, die Datenbankzugriff in Codeausführung verwandelt: Der datenbankgestützte Smarty-Template-Cache kann dazu gebracht werden, vom Angreifer kontrolliertes PHP zu rendern. Die meisten Shops nutzen ihn nie. Deaktivieren Sie ihn vollständig in config/smarty.config.inc.php, sodass er unerreichbar wird:
// AFTER: the MySQL cache include is permanently switched off
if (false /* CVE-2022-36408 mitigation: MySQL Smarty cache disabled */) {
include _PS_CLASS_DIR_.'Smarty/SmartyCacheResourceMysql.php';
$smarty->caching_type = 'mysql';
}
Bestätigen Sie danach, dass der Shop Filesystem-Caching nutzt (PS_SMARTY_CACHING_TYPE = filesystem). Eine SQL-Injection allein ist ernst; eine SQL-Injection, die ein PHP-Template in einen Cache schreiben und ausführen kann, ist eine vollständige Übernahme.
2.3 Verlassene Module (RevSlider und Co.)
Alte, nicht gewartete Module sind ein wiederkehrender Vektor. Wenn Sie ein Modul nicht entfernen können, weil das Theme davon abhängt, verbieten Sie die direkte Web-Ausführung seiner Skripte. Das Frontend-Rendering läuft serverseitig über PrestaShop-Hooks, nicht durch direkten Aufruf der PHP-Dateien des Moduls:
# modules/<module>/.htaccess
<FilesMatch "\.php$">
Require all denied
</FilesMatch>
Und sperren Sie die statischen Eintrittsdateien, die ein Angreifer nach jeder Bereinigung erneut ins Visier nimmt. Auf Dateisystemen mit erweiterten Attributen (ext4/xfs/btrfs): chattr +i index.php config/*.php. Eine künftige Shell kann eine unveränderliche Datei nicht überschreiben, ohne zuvor chattr -i auszuführen, was Root erfordert.
3. Sperren Sie die PHP-Laufzeit – richtig
Die Funktionen zu deaktivieren, die eine Shell zum Starten von OS-Prozessen nutzt, lohnt sich, ist aber der am häufigsten falsch ausgeführte Schritt – auf eine Weise, die angewendet aussieht, es aber nicht ist.
disable_functions = exec,system,shell_exec,passthru,popen,proc_open,
proc_close,proc_get_status,proc_terminate,dl,show_source,phpinfo
Drei Dinge, die übersehen werden:
disable_functionsistPHP_INI_SYSTEM. Es wird nur aus der Start-php.inides SAPI durchgesetzt, das die Seite tatsächlich ausliefert. Auf einer panelverwalteten Maschine ist das Web-SAPI häufig ein bestimmter PHP-FPM-Pool oder eine versionsspezifische Apache-Instanz – nicht das System-CLI-PHP. Bearbeiten Sie die richtigephp.iniund starten Sie genau diesen Dienst neu, sonst bewirkt Ihre Änderung nichts.ini_get('disable_functions')lügt. Es kann eine vollständige Sperrliste melden, die nicht tatsächlich durchgesetzt wird. Der einzige verlässliche Test ist ein echter, über das Web ausgeführter: ein temporäres Skript (zufälliger Name, sofort gelöscht), dasfunction_exists('exec')aufruft und@exec('id')versucht, per HTTP abgerufen. Vertrauen Sie dem Ergebnis des Versuchs, nicht der gemeldeten Konfiguration.- Es ist kein Not-Aus. Es hindert eine PHP-Shell daran, OS-Befehle auszuführen. Es neutralisiert keine PHP-
eval-Shell – diese kann weiterhin Dateien innerhalb vonopen_basedirlesen und schreiben und mit den Zugangsdaten ausparameters.phpauf die Datenbank zugreifen. Betrachten Sie es als eine Schicht, nicht als die Antwort.
Der PrestaShop-Kern nutzt exec() in einigen Bild-/MIME-Pfaden, die finfo-Fallbacks haben, sodass das Deaktivieren Uploads nicht bricht – testen Sie Bild-Uploads trotzdem auf Staging, bevor Sie es live anwenden.
4. Stellen Sie Cloudflare davor – als virtuelle Patch-Schicht
Ein Reverse-Proxy-WAF ist das, was einem virtuellen Patch am nächsten kommt und sich in Minuten ausrollen lässt. Aber es funktioniert nur, wenn Angreifer nicht darum herumrouten können.
4.1 Sperren Sie den Origin auf Cloudflare
Ein WAF vor einem Origin, das noch auf seiner öffentlichen IP antwortet, ist aus Sicht des Angreifers optional. Beschränken Sie die Web-Ports des Servers so, dass nur Cloudflare sie erreichen kann:
# allow 80/443 only from Cloudflare's published ranges, drop the rest
iptables -N CF_WEB
iptables -A CF_WEB -s 173.245.48.0/20 -j ACCEPT # × Cloudflare's IPv4 ranges
# (+ the IPv6 ranges, + 127.0.0.1)
iptables -A CF_WEB -j DROP
iptables -I INPUT -p tcp -m multiport --dports 80,443 -j CF_WEB
Der Haken, den die meisten übersehen: Ihr Mail-DNS verrät die Origin-IP. Ein MX-Eintrag, ein SPF-Eintrag oder eine grau-gewolkte mail.-Subdomain reicht dem Angreifer die echte Adresse – und es ist die obige Firewall, die dieses Leck für das Web harmlos macht. Proxen Sie jeden Web-Eintrag über Cloudflare und schützen Sie den Origin ohnehin per Firewall. Lassen Sie SSH, Mail und Ihre Panel-Ports auf ihren eigenen Zugriffsregeln – die Web-Sperre sollte sie nie berühren.
4.2 WAF-Custom-Rules – und die Endungsfalle
Im Cloudflare-Free-Plan erhalten Sie fünf Custom-Rules und keine regulären Ausdrücke (nur contains, eq, starts_with, ends_with, lower()). Das reicht für ein fokussiertes Regelset:
- Web-Shells & ausführbare Uploads blockieren: bekannte Shell-Namen, direkte Aufrufe von PHP verlassener Module und PHP-Ausführung unter Asset-Verzeichnissen (
/img/,/upload/,/themes/,/js/,/cache/). - Injection-Nutzlasten blockieren:
../,/etc/passwd,union select,information_schema,<?php,base64_decodeund die kodierten Varianten. - Sensible Dateien blockieren:
/.git/,/.env,composer.json, Ihre Konfigurationsdateien. - Die schlimmsten lästigen Crawler per User-Agent blockieren.
Die Falle: Apache führt oft mehr als .php aus. Eine typische AddType-Zeile mappt .php .php3 .php4 .phtml auf den PHP-Handler. Eine Regel, die .phtml/.phar/.php5 blockiert, aber .php3 und .php4 vergisst, lässt eine Shell-Upload-Tür offen – genau diese Lücke fanden wir bei der Überprüfung in unserem eigenen Regelset. Blockieren Sie jede Endung, die der Server tatsächlich ausführt, und prüfen Sie Ihre reale AddType/AddHandler-Konfiguration, statt zu raten.
4.3 Rate-Limiting: Wissen, was Ihr Plan kann und was nicht
Rate-Limiting ist das richtige Werkzeug gegen die Crawler-Fluten, die die Facettensuche überrennen (diesen DoS-Aspekt haben wir separat behandelt). Seien Sie aber genau bezüglich Ihres Tarifs. Im Cloudflare-Free-Plan kann die einzelne Rate-Limit-Regel nur auf den URL-Pfad matchen – nicht auf den Query-String, nicht auf den User-Agent, nicht auf die Quell-IP –, ihre Aktion ist auf block begrenzt und das Fenster ist fest. Das bedeutet, Sie können auf Free keine Regel „Bots auf ?q=-Facetten-URLs drosseln“ bauen; der Query-String ist für sie unsichtbar. Das Beste ist ein Per-IP-Flutlimit auf nicht-statischen Pfaden. Echtes Query- und User-Agent-bewusstes Rate-Limiting (mit Managed Challenge statt hartem Block) erfordert das Advanced Rate Limiting des Pro-Plans. Entscheiden Sie, ob die Exposition der Facettensuche das Upgrade rechtfertigt – für einen aktiv angegriffenen Shop oft ja.
5. Erkennung hinzufügen – damit Runde zwei in Stunden erkannt wird
Härtung senkt die Wahrscheinlichkeit; sie macht Sie nicht immun. Der Unterschied zwischen einem schlechten Nachmittag und einem meldepflichtigen Vorfall ist, wie schnell Sie es bemerken. Der Shop in unserer Fallstudie skimmte fast zwei Tage lang still, bevor jemand hinsah. Behalten Sie ihn im Auge:
- Datei-Integritätsüberwachung (AIDE, Wazuh, OSSEC oder ein einfacher Cron mit gehashtem Manifest) über dem Webroot, mit Alarm bei jedem neuen oder geänderten PHP außerhalb eines Deployments.
- Geplante IOC-Scans nach den Mustern aus echten Angriffen – siehe die Indikatoren in unserem Anatomie-Beitrag – plus jede neue Datei mit ausführbarer Endung in Asset- oder Upload-Verzeichnissen.
- Cloudflare-Security-Events-Review nach Plan, nicht nur nach einem Vorfall. Ihr WAF ist auch ein Sensor.
6. Die Heilung ist weiterhin die Migration
All das oben ist Defense-in-Depth auf Software, die keine Sicherheitsupdates mehr erhält. Es erhöht die Angriffskosten, schließt die aktiv ausgenutzten Türen und kauft Ihnen die Wochen oder Monate, die eine echte Migration braucht – aber es kauft Zeit, nicht Sicherheit. Der Shop in unserer Fallstudie ist genau dafür der Beweis: Er wurde bereinigt, und derselbe Akteur kam durch einen Anwendungsfehler zurück, den die Bereinigung nicht gepatcht hatte. Planen Sie den Umstieg auf PrestaShop 8 oder 9, auf sauberer Infrastruktur, mit Rotation aller Zugangsdaten, als die eigentliche Behebung. Betrachten Sie die Härtung hier als das, was bis dahin das Licht anlässt.
Zu den umliegenden Stücken: die Härtungs-Checkliste als Grundlage, Admin-/2FA-Härtung und .htaccess-Regeln für die Eintrittspunkte sowie unser Leitfaden zur Vorfallsreaktion für den Fall, dass das Schlimmste bereits passiert ist. Und die Anatomie des Angriffs, die jeden Schritt oben motiviert hat.
Kommentare
Noch keine Kommentare. Seien Sie der Erste!
Stellen Sie als Erster eine Frage oder teilen Sie hilfreiches Feedback.
Kommentar schreiben
Teilen Sie eine Frage, ein Installationsdetail oder Feedback, das anderen Lesern helfen kann.