Добрый день.

В предыдущей публикации я рассказывал как, легко и непринужденно, можно настроить сбор метаданных сетевого трафика на маршрутизаторах Микротик в базу данных.

Теперь настало время научить наш сервер делать элементарный анализ получаемых данных и отправлять команды обратно.

Цель: Динамическое управление правилами фаервола Микротик для пресечения сетевых атак с перебором пароля.

Средства: Свежий дистрибутив Linux с rsyslogd v8, crond, СУБД mariadb и собственно сам маршрутизатор Микротик.

Механика: С помощью назначенного задания, выполняется SQL запрос в БД с накопленными и пополняемыми данными трафика и возвращает список исходящих ip-адресов, запускаемый кроном bash скрипт формирует команды Микротика и с помощью ssh соединения, пополняет список адресов для имеющихся правил блокировки.

Речь пойдет о защите открытых TCP портов. Это могут быть входящие на Микротик и пробрасываемые в локальную сеть порты.

Для начала обозначим где могут быть слабые места:

  • Управляющие протоколы маршрутизатора ssh, telnet, web, winbox
  • Почтовые службы smtp, pop, imap
  • Любые веб сервисы предоставляемые наружу
  • Удаленный рабочий стол MS RDP, VNC и т.д.
  • Что-либо другое, на ваше усмотрение

Пишем запрос SQL для поиска брутфорсера

В нашей организации есть терминальные серверы открытые наружу по не приоритетным портам.
В DNAT Микротика я включил логгирование необходимых правил добавив префикс RDP_DNAT. По этому префиксу мы и будем производить поиск:

MariaDB [traflog]> select src,dport,count(dport) as 'попытки подключения' from traffic where datetime>now() - interval 1 day and logpref='RDP_DNAT' group by src having count(dport)>50;
+-----------------+-------+---------------------------------------+
| src             | dport | попытки подключения                   |
+-----------------+-------+---------------------------------------+
| 185.156.177.58  | 12345 |                                   118 |
| 185.156.177.59  | 12345 |                                   267 |
| 193.238.46.12   | 12345 |                                   318 |
| 193.238.46.13   | 12345 |                                   319 |
| 193.238.46.99   | 12345 |                                   342 |
| 194.113.106.150 | 12345 |                                    67 |
| 194.113.106.152 | 12345 |                                   167 |
| 194.113.106.153 | 12345 |                                   190 |
| 194.113.106.154 | 12345 |                                   192 |
| 194.113.106.155 | 12345 |                                   190 |
| 194.113.106.156 | 12345 |                                   216 |
| 194.113.106.158 | 12345 |                                   124 |
+-----------------+-------+---------------------------------------+
12 rows in set (0.06 sec)

Этот запрос показывает ip адрес (с которого идет атака), порт на который происходит подключение (номер порта изменен) и количество попыток подключения, с предварительной группировкой по src и выборкой строк, с количеством попыток более 50 за прошедшие, от текущего момента, сутки.

В моем случае, эти адреса можно смело банить, так как количество подключений у «хороших» клиентов меньше, не более 5-10 в сутки с одного ip.

Запрос работает нормально, быстро, но он длинноват. Для дальнейшего использования я предлагаю сделать представление (view), что бы в будущем меньше копипастить:

MariaDB [traflog]> create or replace view rdp_brute_day as select src, dport, count(dport) from traffic where datetime>now() - interval 1 day and logpref='RDP_DNAT' group by src having count(dport)>50;
Query OK, 0 rows affected (0.23 sec)

Проверим как работает вьюшка:

MariaDB [traflog]> select src,count(dport) from rdp_brute_day;
+----------------+--------------+
| src            | count(dport) |
+----------------+--------------+
| 185.156.177.58 |           11 |
+----------------+--------------+
1 row in set (0.09 sec)

Отлично.

Добавляем пользователя Микротик с авторизацией по ключу dsa

В консоли linux генерируем ключ dsa, под пользователем, от имени которого будет запускаться назначенное задание, я делал из под root:

root@monix:~# ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/root/.ssh/id_dsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_dsa.
Your public key has been saved in /root/.ssh/id_dsa.pub.
...

Passphrase назначать не надо. Публичный ключ /root/.ssh/id_dsa.pub копируем на Микротик любым доступным способом. Я вывел его командой cat, скопировал текст из окна putty в текстовый файл, сохранился и перетащил в окно winbox files.

Не знаю почему, но при выполнении следующих операций через интерфейс winbox что-то пошло не так. При подключении с сервера через ssh, Микротик запрашивал у меня еще и пароль. После того, как удалил созданного пользователя и выполнил все операции через консоль, подключение по dsa заработало. Делал примерно, как описано тут.

В общем я получил желанный вход без пароля по ключу dsa и выполнил проверочную команду:

root@monix:/# ssh rsyslogger@192.168.0.230 /system resource print
             uptime: 2w1d5h22m43s
            version: 6.43.2 (stable)
...

Хорошо.

Пишем bash скрипт

Скрипт получился не сложный:

mikrotik_cmd_list(){
        brute_src_list=$(mysql --skip-column-names traflog  -e 'select src from rdp_brute_day')
        for src in $brute_src_list
                do
                echo "ip firewall address-list add address=$src list=rdp_banlist timeout=1d"
                done
        }

mikrotik_cmd_list | ssh rsyslogger@192.168.0.230

Для того чтобы передать все команды в рамках одного ssh соединения, мне понадобилось описать функцию mikrotik_cmd_list(), в которой сначала выполняется запрос с сохранением ip адресов в переменную brute_src_list, далее в цикле эта переменная последовательно формирует команды для Микротика. После вызова функции, вывод направляется через трубу в ssh.

Не забываем закрыть права доступа к скрипту всем кроме root и делаем файл исполняемым.
Команда которую генерирует скрипт, добавит ip адрес в rdp_banlist на 1 день, по истечении этого времени он сам удалится из списка. Если хотите оставить его навсегда, уберите опцию timeout.

Добавляем правило в фаервол

Я придумал два варианта, как использовать список rdp_banlist:

Вариант первый: добавить список rdp_banlist с восклицательным знаком в правила NAT имеющие префикс RDP_DNAT.

add action=dst-nat chain=dstnat comment="..." dst-address=1.2.3.4 dst-port=12345 log=yes log-prefix=RDP_DNAT protocol=tcp src-address-list=    !rdp_banlist to-addresses=192.168.200.181 to-ports=3389

Примерно так. То есть днатим все, кроме того, что есть в rdp_banlist.

В этом варианте есть плюс и минус.

Плюс в том, что подключения тут же прекратятся.

Минус в том, что больше этот ip не будет попадать в БД traflog и по истечении суток, когда пройдет таймаут хранения в блэклисте, он снова начнет гадить.

Вариант второй: добавить список rdp_banlist с восклицательным знаком в правило firewall цепочки forward, где мы разрешаем прохождение трафика на TCP 3389, аналогично тому, как это сделали в первом способе.

add action=accept chain=forward comment="..."  dst-port=3389 log=yes log-prefix=ACCEPT_RDP protocol=tcp src-address-list=    !rdp_banlist to-ports=3389

Примерно так. Разрешаем все, кроме того, что в банлисте.

Тут тоже плюс и минус.

Плюс. В БД traflog будут продолжать сыпаться логи с префиксом RDP_DNAT, по которым мы определяем признак атаки. В результате, когда закончится таймаут бана определенного хоста, продолжающего попытки брутфорса, он вновь будет добавлен в банлист после очередного запуска назначенного задания.

Минус в том, что он продолжает гадить в таблицу DSTNAT, каждым своим подключением создавая новую запись, пусть и временную.

В общем решение за вами, я выбрал оба :) (на самом деле, в таком случае работает только первый), так как второй у меня был включен раньше и механика там была другая, основанная на последовательной записи в списки stage1, stage2, stage3, banlist… ну вы поняли. Старый и не очень надежный фокус, может легко забанить «хороших» клиентов и при этом пропустить «плохих», вежливо расчитавших таймаут stage1.

Назначенное задание crontab

Осталось добавить назначенное задание в кронтаб:

root@monix:/root# echo '12 *    * * *   root    /usr/share/traflog/scripts/rdp_brute.sh >/dev/null 2>&1' >> /etc/crontab

Такая запись будет запускать скрипт каждый час в 12 минут.

Надо признаться, я только сегодня закончил работу над этой механикой и с большой долей вероятности, что-то может пойти не так. По обстоятельствам буду дополнять и исправлять ошибки. Хочется пить спать спокойно в новогодние праздники, потому и тороплюсь закончить.
Вот пожалуй и все.

Всем спасибо за внимание и с наступающим Новым Годом!

Список литературы:

Документация по mysql
Документация по Mikrotik firewall
Спасибо Андрею Смирнову за статью про подключение по ключу dsa.

Комментарии (24)


  1. KrechTech
    29.12.2018 08:53

    Это работа ради работы?
    В Wiki Mikrotik есть статья «Bruteforce login prevention» как сделать ip firewall filter для защиты от брутфорса.
    Или я чего-то не понял?


    1. sergio_sd Автор
      29.12.2018 09:34

      В какой-то степени да, это скорее работа ради опыта, но это не умоляет ценности.
      Я не прав в том, что опустил эту деталь в самый низ и не сказал об этом сразу.
      Я использую механику защиты от брутфорса предлагаемую Микротиком, но мне не нравится как она работает.
      Во первых: брутфорсер бывает хитрый, он высчитывает таймаут stage1, и делает так что его ip не попадают в блэклист.
      Во вторых: что бы эта механика работала лучше я бы сделал более трех этапов проверки перед баном(штук 6 или даже 9, чем больше тем лучше), но это нагромождение.
      Поясню, интересный факт, при отправке почты через мобильные сети, по какой-то причине последовательно прилетает 3 SYNа, то есть фактически устанавливается 3 соединения и ip src сразу попадает аж на третий этап(заключительный этап), который держит его там, допустим, 2 минуты. При попытке отправить еще что-нибудь, он попадает в банлист. Это неприятно, особенно для директора с его iphone.


    1. sergio_sd Автор
      29.12.2018 09:47

      И да, забыл сказать.
      Цифры полученные в первом SQL запросе (с которого начиналась статья) были при уже включенном «Bruteforce login prevention».


  1. x86128
    29.12.2018 09:55

    По-хорошему, количество записей в банлисте нужно ограничить. Возможна ситуация когда добавится много правил и будет тормозить маршрутизация, либо тормозить процесс изменения этого списка.


    1. sergio_sd Автор
      29.12.2018 11:03

      Возможно. Есть идеи как отследить торможение маршрутизации и процесс добавления в список?
      Пока банлист держит запись сутки, буду наблюдать за динамикой появления новых записей.


      1. x86128
        29.12.2018 15:02

        Через систему мониторинга отслеживать среднюю загрузку CPU (это можно отследить по SNMP), но это только примерная будет оценка, если выше 60-70% тогда начинайте искать проблему.
        С изменением банлиста — логировать на график время работы вашего обновляющего скрипта, а также сделать триггер на время отработки скрипта, если оно раза в три больше обычного то паниковать.


  1. iig
    29.12.2018 10:12

    В крайней версии openssh ключи DSA объявлены deprecated.


    1. sergio_sd Автор
      29.12.2018 11:05

      Что посоветуете? RSA?


      1. iig
        29.12.2018 16:00

        Я бы посоветовал не использовать протоколы, которые брутфорсить, для удаленного доступа к внутренним ресурсам :). Радикально, да. VPN с авторизацией по ключам, и пусть подбирают пароль root.


  1. BigElectricCat
    29.12.2018 10:55

    Вам лучше сделать обратную фишку: отследить длительность сессии и легитимные адреса подключающиеся к вашему RDP и уже получив список легитимных адресов и длительности автоматически корректировать время интервала блокировки нарушителей.


    1. sergio_sd Автор
      29.12.2018 11:15

      Это будет уже искусственный интеллект )
      Как предлагаете отслеживать длительность сессии? Есть вариант вычислять время между приходом SYN и FIN, с соответствующими src:sport dst:dport, но FIN может и не прилететь.
      Автоматически корректировать таймаут, да, идея хорошая, пожалуй нарушителей можно вычислить и по другим признакам, обычно атаки проходят в промежутках времени и повторяются в скором времени. Надо понаблюдать.


    1. sergio_sd Автор
      29.12.2018 11:22

      Для RDP у меня есть другая идея.
      Все тот же Rsyslog должен собирать логи windows, отправляемые, например, с помощью evtsys(связка мне уже знакома, я использовал её ранее). Но для хранения тут уже понадобится mongodb, логи windows по своему формату не очень читаемы. До прикручивания монги я еще не добрался, но руки чешутся. При таком решении, анализ можно будет проводить уже на уровне аудита системы и открываются широкие перспективы.


      1. Naves
        29.12.2018 12:09

        А я вам снова посоветую ELK-стек, и специальный компонент для windows-серверов winlogbeat
        www.elastic.co/videos/getting-started-with-winlogbeat


        1. sergio_sd Автор
          29.12.2018 12:58

          Спасибо, будут смотреть в сторону ELK.


  1. Louie
    29.12.2018 11:22

    Простите великодушно, но задача из разряда «как приличной девушке ходить ночью топлесс, отгоняя приставал газовым баллончиком. выбираем баллончик». 21 век. В интернете повсеместно ssl, любая китайская мыльница умеет в l2tp/ipsec, у микротиков vpn на любой вкус, а вы о брутфорсе-пробросе rdp. Не надо так


    1. sergio_sd Автор
      29.12.2018 11:57

      Хе-хе, прикольная аналогия.
      Я рассматривал этот вариант первым делом, как только приступил к своим обязанностям.
      Но понял, что мои секьюрные рвения никто не оценил. Так как прикручивание клиентов через ipsec/l2tp несет за собой много неудобств для самих пользователей и как следствие головную боль админу. Это в первую очередь, но положим мы справились. А теперь представьте что вы приехали в гости, и вам нужно срочно подключиться по RDP к вашему рабочему серверу и выполнит некоторые действия в 1С, делать на смартфоне это мука, а что бы подключится с компа, вам нужно сначала настроить ipsec/l2tp ) но вы не админ, или админ но у вас нет ключа-сертификата или PSK. И снова головная боль админу, а он катается на лыжах где-нибудь в лесу :)
      Про маршрутизацию в туннель и совместимость адресного пространства дома и работы я даже и говорить не буду, это жопа жопная для простого человека(не админа).


      1. iig
        29.12.2018 14:41

        вы приехали в гости, и вам нужно срочно подключиться по RDP к вашему рабочему серверу

        Не нужно такого хотеть.


        1. x86128
          29.12.2018 15:04

          Сейчас есть автоматические вирусы, которые заходят в 1С по RDP и шифруют базу. Ни с телефона, ни с гостевого компьютера никогда не делайте этого.


          1. gecube
            30.12.2018 18:52

            Полностью поддержу, что нужно ходить только через vpn.
            Заранее можно озаботиться максимально широким спектром настроек для различных устройств (заскриншотить ключевые моменты и добавить в доку). И сделать для всех потенциальных пользователей аккаунты (вероятно, в пределе — для всех) и сервис самовосстановления данных по смс.
            В остальном — rdp наружу — это практически 100% дыра в безопасности. Т.к. может быть и уязвимость в tcp стеке рдп-сервера, так и в протоколе rdp

            А плодить jump-терминалы — так себе идея


    1. sergio_sd Автор
      29.12.2018 12:03

      И кстати хоть в публикации идет речь про RDP, но это все лишь частный случай, просто пример предоставленный для демонстрации плюшек получаемых при сборе и анализе логов маршрутизатора.
      Широкий простор для мечты и для жизни,
      Логи в БД открывают для нас…


      1. gecube
        30.12.2018 18:59

        Это вопрос философский теперь. Работает ли вообще бан по ip?
        Учитываем, что


        • умные брутеры уже давным-давно пользуются широкими пудами адресов (бот-неты, провайдеры с динамическим ip, в конце-концов, облачные провайдеры с виртуалками с эфемерными ip)
        • потихонечку — распространение ipv6 (не напасешься ОЗУ и проца, чтобы лочить эти адреса)
        • провайдеров, предоставляющих "серые" ip клиентам и использующие nat для выхода в интернет, а таковых на российском рынке большинство (что мобильные операторы, что стационарные — вроде Ростелеком).
          Представьте себе радость генерального, когда он с мобильного телефона не сможет зайти на сервер, потому что случайно пошарил адрес с брутфорсером ?!?!?!


        1. sergio_sd Автор
          30.12.2018 01:37

          | 194.113.106.150 | 12345 | 67 |
          | 194.113.106.152 | 12345 | 167 |
          | 194.113.106.153 | 12345 | 190 |
          | 194.113.106.154 | 12345 | 192 |
          | 194.113.106.155 | 12345 | 190 |
          | 194.113.106.156 | 12345 | 216 |
          | 194.113.106.158 | 12345 | 124 |

          Наглядный пример широкого пула адресов. Возможно и шире, надо подумать как за этим следить.

          Серые адреса да, проблема, но я пока не видел, что бы с них прилетали подобные атаки.


  1. gangz
    30.12.2018 01:02

    Сам бился над подобным вопросом, как лучше банить брутфорсеров, в итоге сильно модифицировал решение с вики микротика.

    Но любой бан по IP приводит к большому количеству, порой, очень неприятных эффектов: от ложных срабатываний до не срабатывания в тех случаях, когда это необходимо.
    Причём, это будет в любом случае, а модификация способов определения бан/не бан позволяет только сократить эти эффекты, но исключить их не удастся.

    Данный же способ — зло, т.к. достаточно представить терминальник, на котором работают 5 человек с одного офиса, а потом, у их провайдера происходит авария и 3-4 обрыва соединения за день… итого, 20 новых подключений за день, IP в бан, а 5 юзеров не смогут работать))


    1. sergio_sd Автор
      30.12.2018 01:09

      Почему же сразу «зло»? если включить фантазию, то возможности реализации аналитики с помощью SQL и bash сильно выше чем возможности которые дает сам Микротик. Или вы считаете что вам удалось модифицировать «зло» предложенное вендором в менее злое «зло» чем возможно сделать с помощью накопленных данных SQL и всего что можно только запустить на linux?
      Вопрос блокировки офиса с 5 сотрудниками решается быстро. Три варианта:
      1 Если они имеют статический ip то просто вносятся в белый лист
      2 Если нет статики им ставится железка поднимающая туннель
      3 Если нет денег на новую железку, они звонят мне, говорят что у них не работает и я за пару кликов удаляю их из банлиста.
      К тому же, редко случается когда у провайдера падает канал пять раз в день, на моей памяти ни разу. Плюс ко всему, представление которым мы выбираем данные из БД можно переписать под свои реалии.

      По поводу «сократить эти эффекты» согласен. Нет антибиотиков которые бы не убивали микрофлору кишечника. Но слышал, врачи говорят, при внутримышечном введении кишечник страдает меньше.