Ochrona paneli administracyjnych Joomla, WordPress i innych za pomocą Fail2ban

Administrując jednym z popularnych systemów CMS (np. Joomla!, WordPress) stajesz się potencjalną ofiarą ataków typu „brute force„, czyli brutalną próbą odgadnięcia nazwy użytkownika i hasła do panelu administracyjnego swojego serwisu. Poza oczywistym ryzykiem odgadnięcia takiego dostępu i konsekwencjami jakie za tym idą to jest to duże obciążenie dla serwera. Jeden z ataków jakie udało mi się zaobserwować na Joomla osiągał około 50 zapytań na sekundę.Odwołania takie można wyłapać w w logach access.log, wygląda to mniej więcej tak i jest ich bardzo dużo

8.8.8.8 - - [15/Jun/2014:17:41:52 +0200] "POST /administrator/index.php HTTP/1.1" 200 1847 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"
8.8.8.8 - - [15/Jun/2014:17:41:52 +0200] "POST /administrator/index.php HTTP/1.1" 200 1847 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"
8.8.8.8 - - [15/Jun/2014:17:41:52 +0200] "POST /administrator/index.php HTTP/1.1" 200 1847 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"
8.8.8.8 - - [15/Jun/2014:17:41:53 +0200] "POST /administrator/index.php HTTP/1.1" 200 1847 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"

Do ochrony przed takimi atakami można wykorzystać usługę fail2ban, którą instaluje się na serwerze i zajmuje się ona ochroną różnych usługi dostępowe, które działają na serwerach (SSH, FTP, poczta). Działanie fail2ban polega na czytaniu logów tych usług w poszukiwaniu błędnych logowań i w przypadku wystąpienia określonej ilości błędnych logowań z jednego adresu IP, umieszczaniu reguły blokującej dostęp do usługi na poziomie firewalla (iptables) na określony czas. Taka blokada uniemożliwia całkowite połączenie się z daną usługą, więc odciąża serwer z obsługi takich zapytań.

Instalacja fail2ban

Jeżeli na naszym serwerze nie ma jeszcze zainstalowanego pakietu fail2ban to instalacja jest bardzo prosta o ile posiadamy jedną z popularnych dystrybucji linuxa. Oczywiście musimy posiadać uprawnienia root, w przypadku Debian/Ubuntu wygląda to następująco.

sudo apt-get install fail2ban

Już po samej instalacji i uruchomieniu usługi powinniśmy być chronieni od ataków na usługę SSH.

Konfiguracja fail2ban polega na utworzeniu filtra dla logów (w katalogu /etc/fail2ban/filter.d) i zdefiniowaniu więzienia (jail) dla naszego serwisu, który będzie wykorzystywał wcześniej zdefiniowany filtr (w pliku /etc/fail2ban/jail.local).

Ochrona Joomla!

Instalujemy rozszerzenie, które doda nam plugin generujący wpis w logu error.log w przypadku błędnego logowania, polecam ten
http://extensions.joomla.org/extensions/access-a-security/site-security/login-protection/25592

Włączamy go i tutaj to wszystko. W fail2ban tworzymy filtr

sudo nano /etc/fail2ban/filter.d/joomla.conf

Wklejamy i zapisujemy

[Definition]
failregex = [[]client <HOST>[]] .* user .* authentication failure.*
ignoreregex =

Definiujemy jail

sudo nano /etc/fail2ban/jail.local

Na końcu pliku wklejamy i zapisujemy

[www-joomla]
enabled = true
port = http,https
filter = joomla
logpath = /path/to/logs/error.log

Musimy tutaj podać własną ścieżkę do logów logpath. Możemy zmienić usługi jakie zostanę zablokowane port. Jeżeli na serwerze działa więcej niż jeden serwis oparty o Joomla i chcemy je wszystkie chronić, musimy dla każdego zdefiniować osobny jail, nadając im unikalne nazwy (tutaj www-joomla). Zauważyłem że nazwa nie może mieć więcej niż 20 znaków.

Ochrona WordPress

Instalujemy wtyczkę WP fail2ban
https://wordpress.org/plugins/wp-fail2ban/

Włączamy ją i tutaj to też wszystko. W fail2ban tworzymy filtr

sudo nano /etc/fail2ban/filter.d/wordpress.conf

Wklejamy i zapisujemy

# Fail2Ban configuration file
#
# Author: Charles Lecklider
#

[INCLUDES]
# Read common prefixes. If any customizations available -- read them from
# common.local
before = common.conf

[Definition]
_daemon = wordpress

# Option: failregex
# Notes.: regex to match the password failures messages in the logfile. The
# host must be matched by a group named "host". The tag "<HOST>" can
# be used for standard IP/hostname matching and is only an alias for
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
# Values: TEXT
#
failregex = ^%(__prefix_line)sAuthentication failure for .* from <HOST>$
            ^%(__prefix_line)sBlocked authentication attempt for .* from <HOST>$
            ^%(__prefix_line)sBlocked user enumeration attempt from <HOST>$

# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =

Definiujemy jail

sudo nano /etc/fail2ban/jail.local

Na końcu pliku wklejamy i zapisujemy

[www-wordpress]
enabled = true
port = http,https
filter = wordpress
logpath = /var/log/auth.log

W tym przypadku ścieżka do pliku logów pozostaje bez zmiany, dlatego, że wtyczka dla WordPress umieszcza wpisy w jednym pliku /var/log/auth.log z które korzystają inne usługi, np. SSH. Ma to tą zaletę, że jeden jail ochroni wszystkie nasze serwisy na WordPress z zainstalowaną wtyczką, ale tą wadę, że w logach nie odróżnimy za który serwis poszedł ban.

Uruchomienie i sprawdzenie

Restartujemy usługę

sudo service fail2ban restart Restarting authentication failure monitor: fail2ban.

i zaglądamy do logów czy wszystko jest tak jak być powinno

sudo tail /var/log/fail2ban.log
2014-06-15 18:31:15,124 fail2ban.server : INFO Exiting Fail2ban
2014-06-15 18:31:15,412 fail2ban.server : INFO Changed logging target to /var/log/fail2ban.log for Fail2ban v0.8.4-SVN
...
2014-06-15 18:31:15,427 fail2ban.jail : INFO Creating new jail 'www-joomla'
2014-06-15 18:31:15,427 fail2ban.jail : INFO Jail 'www-joomla' uses poller
2014-06-15 18:31:15,427 fail2ban.filter : INFO Added logfile = /path/to/logs/error.log
2014-06-15 18:31:15,428 fail2ban.filter : INFO Set maxRetry = 6
2014-06-15 18:31:15,429 fail2ban.filter : INFO Set findtime = 600
2014-06-15 18:31:15,430 fail2ban.actions: INFO Set banTime = 600
...
2014-06-15 18:31:15,554 fail2ban.jail : INFO Creating new jail 'www-wordpress'
2014-06-15 18:31:15,554 fail2ban.jail : INFO Jail 'www-wordpress' uses poller
2014-06-15 18:31:15,554 fail2ban.filter : INFO Added logfile = /var/log/auth.log
2014-06-15 18:31:15,555 fail2ban.filter : INFO Set maxRetry = 6
2014-06-15 18:31:15,555 fail2ban.filter : INFO Set findtime = 600
2014-06-15 18:31:15,556 fail2ban.actions: INFO Set banTime = 600
...
2014-06-15 18:31:15,639 fail2ban.jail : INFO Jail 'www-joomla' started
2014-06-15 18:31:15,639 fail2ban.jail : INFO Jail 'www-wordpress' started

Jak widać po logach wszystko powinno działać. Standardowo fail2ban ma ustawioną maksymalną ilość błędnych logowań na 6 (maxRetry = 6) w czasie 10 minut (findtime = 600) i daje bana na 10 minut (banTime = 600). Można to pozmieniać wg. własnego uznania dopisując w jail (plik /etc/fail2ban/jail.local).

Teraz można się błędnie zalogować do panelu Joomla lub WordPress i zobaczyć czy wszystko działa. Po każdym błędnym logowaniu powinniśmy dostać taki wpis w logu error.log naszego serwisu na Joomla.

sudo tail /path/to/logs/error.log
[Sun Jun 15 18:45:03 2014] [warn] [client 8.8.8.8] mod_fcgid: stderr: user test authentication failure

i WordPress

sudo tail /var/log/auth.log
Jun 15 19:34:51 vm8w wordpress(dunowski.pl)[5260]: Authentication failure for test from 8.8.8.8

A po 6 błędnych logowania taki wpis w logu fail2ban

sudo tail /var/log/fail2ban.log
2014-06-15 18:45:05,825 fail2ban.actions: WARNING [www-joomla] Ban 8.8.8.8

a po 10 minutach unban

sudo tail /var/log/fail2ban.log
2014-06-15 18:55:05,989 fail2ban.actions: WARNING [www-joomla] Unban 8.8.8.8

Fail2ban na potrzeby każdego jail tworzy osobny chain w iptables do którego odwołanie znajduje się w INPUT.

sudo iptables -L
Chain INPUT (policy DROP)
target prot opt source destination
fail2ban-www-joomla tcp -- anywhere anywhere multiport dports www,https
fail2ban-www-wordpress tcp -- anywhere anywhere multiport dports www,https
...
Chain fail2ban-www-joomla (1 references)
target prot opt source destination RETURN all -- anywhere anywhere

Chain fail2ban-www-wordpress (1 references)
target prot opt source destination RETURN all -- anywhere anywhere

Przy restarcie fail2ban wszystkie istniejące bany zostają usunięte.

Inne serwisy

Na razie nie miałem do czynienia pod tym kątem z innymi systemami CMS, sklepami internetowymi itp. ale na pewno do każdego popularnego, bez większego znajdziemy dodatek współpracujący z fail2ban.

Możemy też w bardzo prosty sposób zaimplementować taki mechanizm we własnym skrycie PHP, wystarczy jedna linijka w miejscu w którym obsługujemy błędną autoryzację

error_log('user ' . $username . ' authentication failure');

W tym przypadku fail2ban konfigurujemy identycznie jak w przypadku Joomla.

W dzisiejszych czasach i mnogości botów szperających po całym Internecie takie zabezpieczenie wydaje się obowiązkowe bez względu na to czy prowadzi się malutki serwis czy duży. Oczywiście adres IP w logach nie jest prawdziwy 🙂