Содержание
Надело как-то, читая логи nginx-а, натыкаться на попытки перебора пароля в админку WordPress. А что если натравить на хакеров неплохой вполне инструмент fail2ban, который мы уже рассматривали. Будем думать, как их подружить.
Прочитал некоторое количество материала в сети, вроде бы всё просто. Но, как водится, пришлось немного поработать напильником.
Прежде всего, как пишут, нам нужно отфильтровать ошибку аутентификации и вернуть статус, отличный от 200 кода. Да, WordPress в случае неверного ввода пароля возвращает тоже 200-ый код (OK). Мы же будем возвращать 401-ый.
Шаг 1. Создадим плагин обработки неверной аутентификации WordPress
Создадим файл 401auth.php в каталоге wp-content/plugins/
<?php
function login_failed_401()
{
error_log("WP LOGIN FAILED for $username");
status_header(401);
}
add_action( 'wp_login_failed', 'login_failed_401' );
?>
(позднее я этот файл модифицирую)
Войдём в админку и активируем этот плагин. Теперь, при неправильной аутентификации мы получим запись в error_log о LOGIN FAILED.
Шаг 2. Создадим фильтр для обработки события
Теперь создадим новый фильтр fail2ban. Для этого перейдём в каталог /etc/fail2ban/filter.d.
и создадим там файл wordpress-auth.conf
[Definition]
failregex = WP LOGIN FAILED.*.client: <HOST>
Запустим проверку:
# fail2ban-regex /var/log/nginx/litl-admin-ru-error.log /etc/fail2ban/filter.d/wordpress-auth.conf
Ни одного срабатывания. Но внимательно перечитав и лог и вывод этой программы увидим, что нет корректного штампа даты, который нужен для фиксирования факта брутфорса (многократная попытка аутентификации за короткий промежуток времени). Вот тут я и присел. Access_log у меня не ведётся (разгрузка дисковой подсистемы), а как кастомизировать error_log у nginx я не нашёл… Тут в голову пришла идея!
А что, если немного модифицировать плагин, ведь получить дату можно и средствами PHP, причём в произвольном формате. Кроме того, переменная $username почему-то не фиксирует имя пользователя. Но мы можем получить его из $_POST[‘log’], поэтому я немного переписал плагин:
...
error_log(date("Y-m-d H:i:s") . " WP LOGIN FAILED for username: $_POST[log]");
...
Таким образом мы получили штамп даты-времени, а так же логин, который использовался для перебора (log – это имя текстового поля ввода логина на странице аутентификации).
Теперь всё заработало! Есть срабатывания в fail2ban-regex! Идём дальше
Шаг 3. Создадим новую “Клетку”
Редактируем файл /etc/fail2ban/jail.conf
, допишем в конце:
[wordpress]
enabled = true
port = http,https
filter = wordpress-auth
logpath = /var/log/nginx/litl-admin-ru-error.log
maxretry = 3
bantime = 3600
Таким образом, на третью попытку неправильной аутентификации с одного IP мы отправим хакера “подождать” на 3600 секунд. Кроме того, в логах фиксируется и login перебора. Аналогично можно было бы фиксировать и пароль, но он нам ни к чему.
Шаг 4. Перезапускаем fail2ban
# /etc/init.d/fail2ban restart
Можно проверить! Всё вышло как нельзя лучше. Кто-то уже попался:
Важное замечание
В такой ситуации можно произвести “выстрел в ногу”. Предположим, такой вектор атаки: формируется подложная ссылка, которая отправляется жертве-администратору. Пройдя по ссылке, админ палит свой IP адрес. Теперь злоумышленник при помощи софта посылает запросы на аутентификацию с обратным адресом админа. Бах! IP админа в блокировку файрволла. Нужно быть внимательнее и оставить себе “чёрный ход” на случай подобной оказии.
Вполне естественно, что теперь при трёхкратном неправильном вводе пароля последует бан на час