Інтеграція Fail2ban з CSF для протидії DDoS на nginx

Набір скриптів ConfigServer Security & Firewall (CSF) спочатку має досить багатими можливостями по організації захисту сервера хостингу Web фільтрування пакетів iptables. Зокрема з його допомогою можна протистояти затоплення атакується хоста пакетами TCP SYN, UDP і ICMP слабкої та середньої сили. Доповнює CSF вбудований Login Failure Daemon (lfd), який здійснює моніторинг журналів на предмет наявності численних невдалих спроб авторизації в різних мережевих сервісах з метою підбору пароля. Такі спроби блокуються шляхом внесення адреси IP зловмисника у чорний список CSF.

Існує інший сторонній інструмент, що реалізує аналогічний функціонал: Fail2ban. Незважаючи на схожість вирішуваних завдань, між lfd і Fail2ban присутній кардинальна відмінність. Перший має закриту архітектуру і підтримує обмежений набір сервісів. У той час як другий дозволяє самостійно розробити фільтри практично під будь-які завдання. Однак сожительствуют CSF і Fail2ban в межах одного сервера погано, оскільки звертаються до правил iptables кілька безцеремонно. Постараємося вирішити цю проблему на прикладі ОС Linux Debian v7.XX amd64 так, що б витягти максимум з можливостей обох інструментів. А як приклад організуємо захист від DDoS атак на nginx.

В моїй конфігурації CSF був спочатку встановлений і налаштований на сервері. Зупинятися на цьому питанні я не буду, матеріалу з нього досить і нічого нового мені сказати нічого. Тому почнемо відразу з установки Fail2ban, після закінчення якої його необхідно зупинити і відключити автозапуск:
service fail2ban stop
update-rc.d-f fail2ban remove


Запускати Fail2ban ми будемо засобами CSF. Для цього необхідно створити скрипт "./etc/csf/csfpost.sh":
#!/bin/sh
/etc/init.d/fail2ban reload


Він забезпечить автоматичне завантаження правил Fail2ban в iptables, якщо CSF буде перезавантажувати свої, наприклад, у разі оновлення.
Ідея інтеграції Fail2ban з CSF будується на тому, що для блокування IP зловмисників перший буде використовувати чорний список другого, а не безпосередньо правила iptables. Однак повністю від iptables в Fail2ban ми не відмовляємося.
Відключаємо всі фільтри в Fail2ban. Більшу їх частину перекриває lfd. Fail2ban будемо використовувати тільки для того, що не підтримує lfd.
sed-i "s|enabled = true|enabled = false|g". /etc/fail2ban/jail.conf


Додаємо підтримку CSF у Fail2ban. Для цього створимо файл налаштувань "./etc/fail2ban/action.d/csf-ip-відмовити.conf" наступного змісту:
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = csf-d <ip> Added by Fail2Ban for <name>
actionunban = csf-dr <ip>


Замінимо для усіх фільтрів Fail2ban дія блокування на створений «csf-ip-відмовити»:
sed-i-e "s|banaction = |banaction = csf-ip-deny\n#banaction = |". /etc/fail2ban/jail.conf


Для особливо настирливих зловмисників передбачена тривала блокування. Реалізується цей механізм шляхом контролю журналу самого Fail2ban. Створюємо файл налаштувань "./etc/fail2ban/filter.d/fail2ban.conf":
[Definition]
# Count all bans in the logfile
failregex = fail2ban.actions: WARNING \[(.*)\] Ban <HOST>
# Ignore our own bans, to keep our counts exact.
# In your config, name your jail 'fail2ban', or change this line!
ignoreregex = fail2ban.actions: WARNING \[fail2ban\] Ban <HOST>


Додаємо в "./etc/fail2ban/jail.conf" наступні рядки:
## fail2ban with CSF to block repeat offenders
[fail2ban]
enabled = true
filter = fail2ban
action = iptables-allports
# sendmail-whois[name=fail2ban]
logpath = /var/log/fail2ban.log
maxretry = 10
# Find-time: 1 day
findtime = 86400
# Ban-time: 1 week
bantime = 604800


Тобто ті з них, хто протягом доби блокувався іншими фільтрами 10 і більше разів, буде заблокований цим фільтром на тиждень. Зверніть увагу, що тут використовується дія «iptables-allports», а не «csf-ip-відмовити». Це не помилка. Так потрібно, що б тривала блокування не опинилася випадково знятої іншими фільтрами.

Тепер на прикладі організації захисту nginx від DDoS атак розглянемо створення правил фільтрації Fail2ban. Почнемо з налаштування nginx, в ньому необхідно задіяти можливості модулів ngx_http_limit_conn_module і ngx_http_limit_req_module. Для цього додаємо наступні рядки в налаштування:
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn perip 100;
limit_conn_zone $server_name zone=perserver:10m;
limit_conn perserver 200;
limit_req_zone $binary_remote_addr zone=reqip:10m rate=10r/s;
limit_req zone=reqip burst=30;


Таким чином, ми встановили ліміти на не більше ніж 100 підключень з однієї IP адреси одноразово зі швидкістю 10-30 нових підключень в секунду і не більше 200 — до одного сайту всього з будь-якої кількості адрес IP. Перевищення буде фіксуватися в журналі помилок, для якого ми налаштуємо фільтри Fail2ban.
Створюємо наступні файли налаштувань.
"./etc/fail2ban/filter.d/nginx-conn-limit.conf"
# Fail2Ban configuration file
#

[Definition]
# Option: failregex
# Notes.: Regexp to catch a generic call from an IP address.
# Values: TEXT
#
failregex = limiting connections by zone.*client: <HOST>

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


"./etc/fail2ban/filter.d/nginx-req-limit.conf"
# Fail2Ban configuration file
#

[Definition]
# Option: failregex
# Notes.: Regexp to catch a generic call from an IP address.
# Values: TEXT
#
failregex = limiting requests.*client: <HOST>

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


"./etc/fail2ban/filter.d/nginx-dos.conf"
# Fail2Ban configuration file
#

[Definition]
# Option: failregex
# Notes.: Regexp to catch a generic call from an IP address.
# Values: TEXT
#
failregex = ^<HOST> -.*"(GET|POST).*HTTP.*"$

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


Додаємо в "./etc/fail2ban/jail.conf":
[nginx-conn-limit]
enabled = true
filter = nginx-conn-limit
action = csf-ip-deny[name=nginx-conn-limit]
logpath = /var/log/nginx/error.log
maxretry = 4
findtime = 21600
bantime = 3600

[nginx-req-limit]
enabled = true
filter = nginx-req-limit
action = csf-ip-deny[name=nginx-req-limit]
logpath = /var/log/nginx/error.log
maxretry = 4
findtime = 21600
bantime = 3600

[nginx-dos]
# Based on apache-badbots but a simple IP check (any IP requesting more than
# 240 pages in 60 seconds, or 4p/s average, is suspicious)
enabled = true
filter = nginx-dos
action = csf-ip-deny[name=nginx-dos]
logpath = /var/log/nginx/access.log
maxretry = 240
findtime = 60
bantime = 3600


Фільтри «nginx-conn-limit» і «nginx-req-limit» будуть блокувати тих, хто перевищує ліміти на підключення до nginx, а «nginx-dos» — тих, хто занадто часто звертається до сайтів: більше 240 сторінок в хвилину.

Часто метою атак є широкою поширена CMS WordPress: перебір паролів і велику кількість запитів XML-RPC. Організуємо захист від них теж.
"./etc/fail2ban/filter.d/nginx-wp-login.conf"
[Definition]
failregex = <HOST> .*POST /wp-login.php
ignoreregex =
"./etc/fail2ban/filter.d/nginx-wp-xmlrpc.conf"
[Definition]
failregex = <HOST> .*POST /xmlrpc.php
ignoreregex =
"./etc/fail2ban/filter.d/nginx-wp-register.conf"
[Definition]
failregex = ^<HOST> .* "GET /wp-login.php\?action=register HTTP/.*" .*$
ignoreregex =
Додаємо в "./etc/fail2ban/jail.conf":
[nginx-wp-login]
enabled = true
filter = nginx-wp-login
action = csf-ip-deny[name=nginx-wp-login]
logpath = /var/log/nginx/access.log
maxretry = 4
findtime = 600
bantime = 3600

[nginx-wp-xmlrpc]
enabled = true
filter = nginx-wp-xmlrpc
action = csf-ip-deny[name=nginx-wp-xmlrpc]
logpath = /var/log/nginx/access.log
maxretry = 4
findtime = 600
bantime = 3600

[nginx-wp-register]
enabled = true
filter = nginx-wp-register
action = csf-ip-deny[name=nginx-wp-register]
logpath = /var/log/nginx/access.log
maxretry = 4
findtime = 600
bantime = 3600


Ось, що можна буде спостерігати в журналі Fail2ban під час атаки DDoS на nginx:
spoiler
2015-01-04 13:44:10,660 fail2ban.actions: WARNING [nginx-req-limit] Ban 188.191.47.46
2015-01-04 13:44:11,668 fail2ban.actions: WARNING [nginx-conn-limit] Ban 109.187.63.199
2015-01-04 13:44:21,061 fail2ban.actions: WARNING [nginx-req-limit] 188.191.47.46 already banned
2015-01-04 13:44:29,382 fail2ban.actions: WARNING [nginx-conn-limit] Ban 178.123.155.115
2015-01-04 13:44:36,584 fail2ban.actions: WARNING [nginx-conn-limit] Ban 109.62.153.190
2015-01-04 13:44:38,246 fail2ban.actions: WARNING [nginx-dos] Ban 5.143.158.88
2015-01-04 13:44:38,826 fail2ban.actions: WARNING [nginx-req-limit] Ban 178.158.206.140
2015-01-04 13:44:41,739 fail2ban.actions: WARNING [nginx-conn-limit] Ban 5.44.168.38
2015-01-04 13:44:49,877 fail2ban.actions: WARNING [nginx-dos] Ban 91.214.131.71
2015-01-04 13:44:52,333 fail2ban.actions: WARNING [nginx-conn-limit] Ban 176.125.48.22
2015-01-04 13:44:53,395 fail2ban.actions: WARNING [nginx-req-limit] Ban 91.207.211.222
2015-01-04 13:44:53,773 fail2ban.actions: WARNING [nginx-dos] Ban 178.158.206.140
2015-01-04 13:44:54,849 fail2ban.actions: WARNING [nginx-conn-limit] Ban 5.143.158.88
2015-01-04 13:44:57,395 fail2ban.actions: WARNING [nginx-req-limit] 91.207.211.222 already banned
2015-01-04 13:44:57,765 fail2ban.actions: WARNING [nginx-dos] Ban 37.232.87.169
2015-01-04 13:44:58,073 fail2ban.actions: WARNING [nginx-conn-limit] Ban 77.34.22.95
2015-01-04 13:44:58,506 fail2ban.actions: WARNING [nginx-req-limit] Ban 93.80.45.244
2015-01-04 13:45:02,733 fail2ban.actions: WARNING [nginx-dos] Ban 176.120.38.238
2015-01-04 13:45:05,615 fail2ban.actions: WARNING [nginx-conn-limit] Ban 178.173.4.162


А ось так будуть блокуватися надмірно настирливі зловмисники:
spoiler
2015-01-04 11:43:29,618 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129
2015-01-04 12:43:30,160 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129
2015-01-04 12:56:53,543 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129
2015-01-04 13:56:54,279 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129
2015-01-04 14:02:40,932 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129
2015-01-04 15:02:41,040 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129
2015-01-04 15:12:16,906 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129
2015-01-04 16:12:16,937 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129
2015-01-04 16:55:33,362 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129
2015-01-04 17:55:34,142 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129
2015-01-04 18:23:37,665 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129
2015-01-04 19:23:38,136 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129
2015-01-04 19:45:46,850 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129
2015-01-04 20:03:17,247 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42
2015-01-04 20:45:47,085 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129
2015-01-04 21:03:17,297 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42
2015-01-04 21:09:51,996 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42
2015-01-04 21:16:22,336 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129
2015-01-04 22:09:52,036 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42
2015-01-04 22:13:27,799 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42
2015-01-04 22:16:23,295 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129
2015-01-04 22:24:56,755 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129
2015-01-04 23:13:28,058 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42
2015-01-04 23:16:50,235 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42
2015-01-04 23:24:56,843 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129
2015-01-05 00:00:42,183 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129
2015-01-05 00:00:43,851 fail2ban.actions: WARNING [fail2ban] Ban 95.163.121.129
2015-01-05 00:16:50,263 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42
2015-01-05 00:23:22,863 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42
2015-01-05 01:00:42,637 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129
2015-01-05 01:23:23,750 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42
2015-01-05 01:26:16,543 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42
2015-01-05 02:26:16,681 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42
2015-01-05 02:32:28,850 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42
2015-01-05 03:32:29,350 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42
2015-01-05 03:39:18,048 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42
2015-01-05 04:39:18,609 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42
2015-01-05 04:43:38,428 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42
2015-01-05 05:43:39,091 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42
2015-01-05 05:47:47,722 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42
2015-01-05 05:47:50,212 fail2ban.actions: WARNING [fail2ban] Ban 92.255.28.42
2015-01-05 06:47:48,343 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42


Останнім часом почастішали випадки, коли зловмисники здійснюють розподілений перебір паролів з різних адрес IP однієї підмережі класу C. Алгоритм роботи Fail2ban не здатний розпізнати таку поведінку:
spoiler
2015-01-05 14:01:14,432 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.176
2015-01-05 14:01:14,656 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.249
2015-01-05 14:01:35,906 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.198
2015-01-05 14:02:39,536 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.154
2015-01-05 14:02:53,766 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.132
2015-01-05 14:02:53,980 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.202
2015-01-05 14:04:00,782 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.136
2015-01-05 14:04:05,007 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.104
2015-01-05 14:04:07,234 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.167
2015-01-05 14:04:25,473 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.143
2015-01-05 14:05:26,993 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.253
2015-01-05 14:06:25,719 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.230
2015-01-05 14:06:27,945 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.162
2015-01-05 14:07:23,484 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.153
2015-01-05 14:07:56,962 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.140
2015-01-05 14:08:11,207 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.142
2015-01-05 14:09:37,759 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.137
2015-01-05 14:10:59,757 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.175
2015-01-05 14:11:04,030 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.117
2015-01-05 14:11:23,273 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.218
2015-01-05 14:11:41,517 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.139
2015-01-05 14:13:22,590 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.204
2015-01-05 14:13:24,808 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.220
2015-01-05 14:14:36,124 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.190
2015-01-05 14:14:38,356 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.179
2015-01-05 14:14:38,577 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.137
2015-01-05 14:14:49,805 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.188
2015-01-05 14:15:48,398 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.131


Усунути цей недолік за допомогою такого скрипту, який буде виконуватися кожен годину планувальником cron.
"./etc/cron.hourly/fail2ban-subnets"
#!/bin/bash

log="/var/log/fail2ban.log"
limit=30
grep=`which grep`

${grep} "fail2ban.actions.*Ban" ${log} | ${grep} -E-o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" | awk-F'.' '{print $1"."$2"."$3}' | sort-u | while read line
do
count=$(${grep} -c "fail2ban.actions.*Ban.*${line}" ${log})
if [ ${count} -ge ${limit} ]
then
/usr/sbin/csf-td ${line}.0/24 7d "Subnet ${line}.0/24 is blocked for a week by Fail2ban after ${count} attempts"
fi
done

exit 0


Тобто мережі IP класу C будуть заблоковані на тиждень цілком, якщо раніше інші фільтри Fail2ban спрацьовували на адреси з них 30 або більше разів.
Ось так виглядає результат:
# csf-t

A/D IP address Port Dir Time To Live Comment
DENY 193.176.147.0/24 * in 6d 21h 34m 18s Subnet 193.176.147.0/24 is blocked for a week by Fail2ban after 641 attempts
DENY 46.148.30.0/24 * in 6d 21h 34m 19s Subnet 46.148.30.0/24 is blocked for a week by Fail2ban after 332 attempts
DENY 46.148.31.0/24 * in 6d 21h 34m 19s Subnet 46.148.31.0/24 is blocked for a week by Fail2ban after 334 attempts


При написанні цієї статті були використані напрацювання з наступних ресурсів:
https://extremeshok.com/5030/ubuntu-lts-fail2ban-with-csf-and-blocking-of-repeat-offenders-scan-log-files-to-ban-malicious-ips-and-prevent-brute-forcing-of-logins-with-configs/
http://tecadmin.net/add-custom-iptables-rules-with-csf/
https://rtcamp.com/tutorials/nginx/block-wp-login-php-bruteforce-attack/
https://rtcamp.com/tutorials/nginx/fail2ban/
https://www.xaker.name/forvb/showthread.php?t=28659
https://beeznest.wordpress.com/2012/06/08/anti-nginx-dos-filter-for-fail2ban-4/
https://debian.pro/1223
http://www.michelem.org/2014/03/02/stopblock-apachenginx-hack-attempts-with-fail2ban/
http://www.krazyworks.com/permanently-ban-ip-with-fail2ban/
http://www.shellhacks.com/ru/RegEx-Nayti-IP-Adresa-v-Fayle-s-Pomoshchyu-Grep

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.