CleanOps

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

3 października 2026 • 3 min czytania • backdoor, .htaccess, Joomla, web-shell

Kod źródłowy na ciemnym ekranie

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.php i lock360.php to nazwy znanych web‑shelli.
  • Reguły RewriteRule na dole wyglądają jak standardowy SEF Joomli, ale w podkatalogu libraries/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ąć

  1. 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 .htaccess wrócą po godzinie.
  2. Potem allowlistowane pliki: shelle o nazwach z listy, w każdym katalogu.
  3. 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ą.
  4. 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.

Czytaj też