Zaawansowane utwardzanie PrestaShop dla sklepów, których nie da się jeszcze zaktualizować
W naszej analizie kryminalistycznej ataku typu Magecart postawiliśmy tezę, która z perspektywy czasu zasługuje na osobny artykuł: usunięcie złośliwego kodu ze sklepu to nie to samo, co naprawienie sklepu. Usunęliśmy skimmer, web‑shelle i binaria SUID‑root z tamtego sklepu PrestaShop 1.7.x — i niedługo później został on zaatakowany ponownie. Nie przez backdoora, którego przeoczyliśmy, lecz przez frontowe drzwi: podatność na poziomie aplikacji, którą sprzątanie powstrzymało, ale nigdy nie zamknęło. Ten wpis to playbook, który chcielibyśmy zastosować za pierwszym razem — jak utwardzić sklep PrestaShop, którego na razie nie da się zaktualizować, tak by usunięcie ładunku zamykało także dziurę, przez którą się dostał.
Jeśli możesz dziś zaktualizować się do PrestaShop 8 lub 9 — zrób to zamiast tego; to jedyne trwałe rozwiązanie, a reszta artykułu to półśrodek. Ale dla nietrywialnego sklepu aktualizacja to projekt na wiele tygodni (zgodność modułów, refaktoryzacja motywu, przepięcie płatności). Okres przejściowy jest realny i przez cały ten czas jesteś celem. Oto jak go przetrwać. To zaawansowane uzupełnienie naszej listy kontrolnej utwardzania PrestaShop — tam zacznij od podstaw, tu wróć po warstwę „incydentową”.
1. Znajdź wektor wejścia, a nie tylko ładunek
Najdroższym błędem w reagowaniu na incydent jest mylenie widocznego objawu z raną. Skimmer w JavaScripcie motywu to objaw. Raną jest to, co w ogóle pozwoliło atakującemu zapisać ten JavaScript — web‑shell, niezałatany moduł, punkt wstrzyknięcia. Usuń skimmer i zostaw ranę otwartą, a kupisz sobie dni, nie bezpieczeństwo.
Zanim cokolwiek utwardzisz, odpowiedz z dowodami na jedno pytanie: jak kod trafił na dysk? Przejrzyj logi dostępu wokół znaczników czasu utworzenia plików złośliwego kodu (używaj ctime, nie mtime — atakujący podmieniają mtime). Skoreluj podejrzane wzorce POST, nietypowe parametry zapytań i anomalie rozmiaru odpowiedzi z momentem pojawienia się ładunku. Jeśli nie potrafisz nazwać wektora wejścia, zakładaj, że nadal jest otwarty.
2. Zastosuj „wirtualne łatki” na znany łańcuch ataku 1.7.x
PrestaShop 1.7.x ma garść dobrze znanych, uzbrojonych podatności, które automatyczne skanery łączą w łańcuch. Jeśli nie możesz zaktualizować, załataj konkretne ścieżki kodu bezpośrednio. To półśrodki — śledź oryginalne komunikaty bezpieczeństwa — ale zamykają drzwi, które są aktywnie wyważane.
2.1 Wstrzyknięcie SQL w wyszukiwaniu fasetowym
Starsze wersje ps_facetedsearch sklejają wartości filtrów bezpośrednio w zapytaniu SQL. To prymityw blind SQL‑injection, a na sklepie 1.7.x bywa to faktyczny punkt wejścia. Escapuj i rzutuj typ każdej wartości pochodzącej z żądania:
// 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 RCE w pamięci podręcznej Smarty MySQL (CVE-2022-36408)
To ta połowa łańcucha, która zamienia dostęp do bazy w wykonanie kodu: bazodanowa pamięć podręczna szablonów Smarty może zostać zmuszona do wyrenderowania PHP kontrolowanego przez atakującego. Większość sklepów nigdy jej nie używa. Wyłącz ją całkowicie w config/smarty.config.inc.php, by była nieosiągalna:
// 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';
}
Potem potwierdź, że sklep korzysta z cache plikowego (PS_SMARTY_CACHING_TYPE = filesystem). Samo wstrzyknięcie SQL jest groźne; wstrzyknięcie SQL, które potrafi zapisać szablon PHP do cache i go wykonać, to pełne przejęcie.
2.3 Porzucone moduły (RevSlider i podobne)
Stare, nieutrzymywane moduły to powracający wektor. Jeśli nie możesz usunąć modułu, bo zależy od niego motyw, zablokuj bezpośrednie wykonywanie jego skryptów przez web. Renderowanie front‑endu odbywa się przez hooki PrestaShop po stronie serwera, a nie przez bezpośrednie wywoływanie plików PHP modułu:
# modules/<module>/.htaccess
<FilesMatch "\.php$">
Require all denied
</FilesMatch>
I zablokuj statyczne pliki wejściowe, które atakujący bierze na cel po każdym sprzątaniu. Na systemach plików obsługujących atrybuty rozszerzone (ext4/xfs/btrfs): chattr +i index.php config/*.php. Przyszły shell nie nadpisze pliku z atrybutem immutable bez uprzedniego chattr -i, co wymaga roota.
3. Zablokuj środowisko PHP — poprawnie
Wyłączenie funkcji, których shell używa do uruchamiania procesów systemu operacyjnego, jest warte zachodu, ale to krok najczęściej wykonywany źle — w sposób, który wygląda na zastosowany, choć nim nie jest.
disable_functions = exec,system,shell_exec,passthru,popen,proc_open,
proc_close,proc_get_status,proc_terminate,dl,show_source,phpinfo
Trzy rzeczy, które się pomija:
disable_functionsjest typuPHP_INI_SYSTEM. Jest egzekwowane wyłącznie ze startowegophp.initego SAPI, które faktycznie obsługuje stronę. Na serwerze zarządzanym panelem web‑SAPI to często konkretna pula PHP‑FPM albo instancja Apache dla danej wersji — nie systemowe CLI PHP. Edytuj właściwyphp.inii zrestartuj dokładnie tę usługę, inaczej zmiana nic nie da.ini_get('disable_functions')kłamie. Może raportować pełną listę blokad, która nie jest faktycznie egzekwowana. Jedyny wiarygodny test to realny, wykonany przez web: tymczasowy skrypt (losowa nazwa, natychmiast usuwany), który wywołujefunction_exists('exec')i próbuje@exec('id'), pobrany przez HTTP. Ufaj wynikowi próby, nie raportowanej konfiguracji.- To nie jest wyłącznik awaryjny. Powstrzymuje shell PHP przed wywoływaniem poleceń systemu. Nie neutralizuje shella opartego na
evalw PHP — taki nadal może czytać i zapisywać pliki w obrębieopen_basediri łączyć się z bazą używając danych zparameters.php. Traktuj to jako jedną warstwę, nie jako rozwiązanie.
Rdzeń PrestaShop używa exec() w paru ścieżkach obróbki obrazów/MIME, które mają fallback przez finfo, więc wyłączenie nie psuje uploadu — ale i tak przetestuj wgrywanie obrazów na środowisku staging przed wdrożeniem na live.
4. Postaw Cloudflare przed sklepem — jako warstwę „wirtualnej łatki”
WAF na reverse‑proxy to najbliższy odpowiednik wirtualnej łatki, jaki wdrożysz w kilka minut. Ale działa tylko wtedy, gdy atakujący nie może go obejść.
4.1 Zamknij origin tylko dla Cloudflare
WAF przed origin, który nadal odpowiada na swoim publicznym IP, jest z perspektywy atakującego opcjonalny. Ogranicz porty web serwera tak, by mógł je osiągnąć tylko Cloudflare:
# 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
Haczyk, który większość pomija: twój DNS poczty zdradza IP origin. Rekord MX, rekord SPF albo nieproxowana subdomena mail. wręcza atakującemu prawdziwy adres — a to właśnie powyższy firewall sprawia, że ten wyciek jest dla części webowej nieszkodliwy. Proxuj każdy rekord webowy przez Cloudflare i tak czy inaczej osłoń origin firewallem. Zostaw SSH, pocztę i porty panelu na ich własnych regułach dostępu — blokada części web nie powinna ich nigdy dotykać.
4.2 Reguły WAF — i pułapka rozszerzeń
W planie Free Cloudflare masz pięć reguł niestandardowych i brak wyrażeń regularnych (tylko contains, eq, starts_with, ends_with, lower()). To wystarcza na skoncentrowany zestaw reguł:
- Blokuj web‑shelle i wgrywanie plików wykonywalnych: znane nazwy shelli, bezpośrednie wywołania PHP porzuconych modułów oraz wykonywanie PHP w katalogach zasobów (
/img/,/upload/,/themes/,/js/,/cache/). - Blokuj ładunki wstrzyknięć:
../,/etc/passwd,union select,information_schema,<?php,base64_decodeoraz warianty zakodowane. - Blokuj wrażliwe pliki:
/.git/,/.env,composer.json, pliki konfiguracyjne. - Blokuj najgorsze uciążliwe crawlery po user‑agent.
Pułapka: Apache często wykonuje więcej niż .php. Typowa linia AddType mapuje .php .php3 .php4 .phtml na handler PHP. Reguła blokująca .phtml/.phar/.php5, ale pomijająca .php3 i .php4, zostawia otwarte drzwi do wgrania shella — dokładnie tę lukę znaleźliśmy w naszym własnym zestawie reguł podczas przeglądu. Blokuj każde rozszerzenie, które serwer faktycznie uruchomi, i sprawdź swoją realną konfigurację AddType/AddHandler, zamiast zakładać.
4.3 Rate‑limiting: wiedz, co twój plan może, a czego nie
Rate‑limiting to właściwe narzędzie przeciw zalewom crawlerów, które katują wyszukiwanie fasetowe (ten aspekt DoS opisaliśmy osobno). Ale bądź precyzyjny co do swojego poziomu. W planie Free Cloudflare pojedyncza reguła rate‑limit może dopasowywać wyłącznie ścieżkę URL — nie query string, nie user‑agent, nie źródłowe IP — jej akcja ogranicza się do block, a okno jest stałe. Oznacza to, że na Free nie zbudujesz reguły „ogranicz boty na fasetowych URL‑ach ?q=”; query string jest dla niej niewidoczny. Najlepsze, co możesz zrobić, to limit zalewu per‑IP na ścieżkach niestatycznych. Prawdziwy rate‑limiting świadomy query stringu i user‑agenta (z managed challenge zamiast twardego bloku) wymaga Advanced Rate Limiting z planu Pro. Zdecyduj, czy ekspozycja wyszukiwania fasetowego uzasadnia upgrade — dla aktywnie atakowanego sklepu często tak.
5. Dodaj wykrywanie — by drugą rundę złapać w godziny
Utwardzanie zmniejsza ryzyko; nie czyni cię odpornym. Różnica między złym popołudniem a incydentem na poziomie obowiązku zgłoszenia to jak szybko zauważysz. Sklep z naszego studium przypadku skimmował po cichu przez prawie dwa dni, zanim ktokolwiek spojrzał. Miej go na oku:
- Monitoring integralności plików (AIDE, Wazuh, OSSEC albo prosty cron z manifestem haszy) nad webrootem, z alertem o każdym nowym lub zmienionym PHP poza wdrożeniem.
- Zaplanowane przeglądy IOC pod kątem wzorców z prawdziwych ataków — patrz wskaźniki w naszym wpisie z anatomią — plus każdy nowy plik o wykonywalnym rozszerzeniu pojawiający się w katalogach zasobów lub uploadu.
- Przegląd Cloudflare Security Events według harmonogramu, nie tylko po incydencie. Twój WAF jest też czujnikiem.
6. Lekarstwem nadal jest migracja
Wszystko powyżej to obrona w głąb na oprogramowaniu, które nie otrzymuje już aktualizacji bezpieczeństwa. Podnosi koszt ataku, zamyka aktywnie wykorzystywane drzwi i kupuje tygodnie lub miesiące, których potrzebuje prawdziwa migracja — ale kupuje czas, nie bezpieczeństwo. Sklep z naszego studium przypadku jest właśnie tego dowodem: został wyczyszczony, a ten sam operator wrócił przez wadę aplikacji, której sprzątanie nie załatało. Zaplanuj przejście na PrestaShop 8 lub 9, na czystej infrastrukturze, z rotacją wszystkich poświadczeń, jako faktyczną naprawę. Traktuj utwardzanie z tego wpisu jako to, co utrzymuje światła zapalone do tego czasu.
Po części uzupełniające: lista kontrolna utwardzania jako podstawa, utwardzanie panelu/2FA i reguły .htaccess dla punktów wejścia oraz nasz przewodnik reagowania na naruszenie na wypadek, gdy najgorsze już się stało. I anatomia ataku, która umotywowała każdy z powyższych kroków.
Komentarze
Brak komentarzy. Bądź pierwszy!
Bądź pierwszy: zadaj pytanie albo podziel się przydatną opinią.
Dodaj komentarz
Dodaj pytanie, szczegół montażu albo opinię, która może pomóc innemu czytelnikowi.