Backdoor w .htaccess — jak atakujący chronią swoje web‑shelle i jak to rozpoznać

Skanery malware szukają kodu: eval, base64_decode, zaciemnionych łańcuchów. Plik .htaccess kodem nie jest, więc większość narzędzi w ogóle go nie czyta. Atakujący o tym wiedzą i od lat używają .htaccess do jednego celu: żeby ich web‑shelle działały, a wszystko inne nie.
Prawdziwy przykład
Podczas naprawy strony na Joomli znaleźliśmy ten plik w ponad 6 tysiącach katalogów — w każdym podkatalogu instalacji:
<FilesMatch ".(py|exe|php)$">
Order allow,deny
Deny from all
</FilesMatch>
<FilesMatch "^(about.php|radio.php|index.php|content.php|lock360.php|admin.php|wp-login.php)$">
Order allow,deny
Allow from all
</FilesMatch>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
Co tu się dzieje:
- Pierwszy blok blokuje wykonywanie wszystkich plików PHP w katalogu. Brzmi jak zabezpieczenie.
- Drugi blok odblokowuje konkretne nazwy:
radio.php,lock360.php,content.php,about.php,admin.php,wp-login.php. Na stronie na Joomli nie ma żadnego powodu, by istniałwp-login.php— to nazwa z WordPressa.radio.phpilock360.phpto nazwy znanych web‑shelli. - Reguły
RewriteRulena dole wyglądają jak standardowy SEF Joomli, ale w podkatalogulibraries/legacy/form/nie mają sensu. Są tam, żeby plik wyglądał „normalnie”.
Efekt: atakujący może wrzucić swój shell pod jedną z allowlistowanych nazw w dowolny z 6 tysięcy katalogów i będzie działał, a jednocześnie konkurencyjni atakujący i skanery dostaną 403 na wszystko inne. To ochrona backdoora przed usunięciem i przed przejęciem przez inną grupę.
Skąd się bierze
W tym samym przypadku root index.php strony miał doklejony na początku zaciemniony blok PHP. Funkcja w nim zawarta (h2()) generowała z base64 właśnie ten .htaccess i zapisywała go rekurencyjnie w katalogach. Druga funkcja odpytywała serwer C2 i serwowała przekierowania wybranym odwiedzającym. Czyli: jeden zainfekowany plik → tysiące plików ochrony.
Jak to znaleźć na swojej stronie
Po SSH, w katalogu strony:
grep -rl "Allow from all" --include=".htaccess" . | head
grep -rlE "lock360|radio\.php|wp-l0gin|gel4y|alfa\.php|wso\.php" --include=".htaccess" . | head
find . -name ".htaccess" -newer configuration.php | wc -l
Legalny .htaccess w podkatalogach WordPressa czy Joomli to rzadkość i niemal nigdy nie zawiera allowlisty konkretnych plików PHP. Jeśli ostatnia komenda zwraca setki lub tysiące plików, masz odpowiedź.
Dodatkowo poszukaj samych shelli — plików o allowlistowanych nazwach:
find . -name "radio.php" -o -name "lock360.php" -o -name "wp-l0gin.php" -o -name "mah.php"
Jak to usunąć
- Najpierw źródło: root
index.php,administrator/index.php, pliki, które generują.htaccess. Porównaj je z oficjalnym wydaniem i przywróć oryginały. Bez tego.htaccesswrócą po godzinie. - Potem allowlistowane pliki: shelle o nazwach z listy, w każdym katalogu.
- Na końcu same
.htaccess: usuń te w podkatalogach (ale zachowaj główny, po przywróceniu w nim standardowych reguł CMS-a). Przy tysiącach plików rób to skryptem i z kopią. - Zmień hasła do CMS, bazy, FTP/SSH. Shell działał z uprawnieniami Twojego konta.
Dlaczego warto rozpoznawać to regułą, nie analizą
W CleanOps ten konkretny wzorzec (blokada .php + allowlista co najmniej dwóch nazw znanych shelli) jest rozstrzygany regułą, bez udziału modelu AI, i trafia prosto do kwarantanny. Powód jest praktyczny: w opisanym przypadku 6 tysięcy identycznych plików trafiło pierwotnie do analizy po kolei, każdy osobno. Dopiero rozpoznawanie sygnatury i współdzielenie werdyktu między identycznymi plikami sprowadziło to do kilku sekund i kilku groszy.
Jeśli chcesz sprawdzić własną stronę bez ruszania plików, sprawdzenie w CleanOps jest bezpłatne i pokaże między innymi dokładnie takie pliki.


