Материал просмотрен 246 раз(а)

Надело как-то, читая логи 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

Можно проверить! Всё вышло как нельзя лучше. Кто-то уже попался:

fail2ban iptables

fail2ban iptables

Важное замечание

В такой ситуации можно произвести “выстрел в ногу”. Предположим, такой вектор атаки: формируется подложная ссылка, которая отправляется жертве-администратору. Пройдя по ссылке, админ палит свой IP адрес. Теперь злоумышленник при помощи софта посылает запросы на аутентификацию с обратным адресом админа. Бах! IP админа в блокировку файрволла. Нужно быть внимательнее и оставить себе “чёрный ход” на случай подобной оказии.