MikroTik + port knocking over ICMP

    Совсем маленький пост рассказывающий, как отловить ICMP пакеты и отфильтровать их с логикой.

    Реализуем технология port knocking на RouterOS через протокол icmp.

    Прошу под кат.

    Наверное нету смысла рассказывать, что такое port knoking, так как в интернете довольно-таки много описаний про него.
    Если совсем кратко то технология позволяет при определённом порядке перебора портов, при условии что перебор выполнен верно, выполнять различные действия.
    Я же вам покажу как можно реализовать данную технологию через протокол ICMP которые не поддерживает порты. И мы будем апеллировать размером ICMP пакета.

    Добавляем себя в white_list


    У нас есть правило в фильтре
    [admin@kirilka] /ip firewall filter> print 
    Flags: X - disabled, I - invalid, D - dynamic 
     0   chain=input action=accept protocol=tcp src-address-list=white_list_ssh in-interface=ether1 dst-port=22 
    

    Которое говорит, что разрешать входящие соединение по 22 порту (ssh), со всех адресов которые содержаться в white_list.
    Добавим два правила
    Зададим критерия, нужна простая проверка уз двух подходов. Пусть будет первых стук пакет размером 70, а второй 100, а также обязательно по два пакета.
    Не забываем, что заголовок пакета ICMP 28 байт.
    И так у нас вырисовывается следующая картина мы должны два раза стукнуться по ICMP с размером пакета 98байт и два раза стукнуться с размером пакета 128 байт.
    Ловим первый пакет с размером 98 байт.

    chain=input action=add-src-to-address-list protocol=icmp address-list=ICMP_SSH_98_stage1 address-list-timeout=1m in-interface=ether2 packet-size=98
    

    Пакет размером 98 байт по протоколу ICMP заносим исходящий адрес в лист ICMP_SSH_98_stage1

    Ловим второй пакет с размером 98 байт.

    chain=input action=add-src-to-address-list protocol=icmp src-address-list=ICMP_SSH_98_stage1 address-list=ICMP_SSH_98_stage2 address-list-timeout=1m  in-interface=ether2 packet-size=98
    

    Пакет размером 98 байт по протоколу ICMP и исходящий адрес уже содержится в листе ICMP_SSH_98_stage1, то заносим исходящий адрес в лист ICMP_SSH_98_stage2

    Мы поймали два пакета по 98 байт или 70 байт при отправлении.
    Ловим третий пакет с размером 128 байт.

    chain=input action=add-src-to-address-list protocol=icmp src-address-list=ICMP_SSH_98_stage2 address-list=ICMP_SSH_128_stage1 address-list-timeout=1m in-interface=ether1 packet-size=128
    

    Пакет размером 128 байт по протоколу ICMP и исходящий адрес уже содержится в листе ICMP_SSH_98_stage2, то заносим исходящий адрес в лист ICMP_SSH_128_stage1

    Ловим четвёртый пакет(последний) с размером 128 байт.

    chain=input action=add-src-to-address-list protocol=icmp src-address-list=ICMP_SSH_128_stage1 address-list=white_list_ssh address-list-timeout=1h in-interface=ether1 packet-size=128
    

    Пакет размером 128 байт по протоколу ICMP и исходящий адрес уже содержится в листе ICMP_SSH_128_stage1, то заносим исходящий адрес в лист white_list_ssh на 1 час.


    Я специально сделал первый пример немного не правильно, чтобы вы смогли увидеть последовательность действий.
    Для того чтобы всё заработало вам необходимо порядок правил переместить в обратном порядке. Смотри под спойлером.


    Полностью таблица фильтров
    [admin@kirilka] /ip firewall filter> print
    Flags: X - disabled, I - invalid, D - dynamic 
     0   chain=input action=accept protocol=tcp src-address-list=white_list_ssh in-interface=ether2 dst-port=22 
    
     1   chain=input action=add-src-to-address-list protocol=icmp src-address-list=ICMP_SSH_128_stage1 address-list=white_list_ssh address-list-timeout=1h in-interface=ether1 packet-size=128 
    
     2   chain=input action=add-src-to-address-list protocol=icmp src-address-list=ICMP_SSH_98_stage2 address-list=ICMP_SSH_128_stage1 address-list-timeout=1m  in-interface=ether1 packet-size=128 
    
     3   chain=input action=add-src-to-address-list protocol=icmp src-address-list=ICMP_SSH_98_stage1 address-list=ICMP_SSH_98_stage2 address-list-timeout=1m in-interface=ether1 packet-size=98 
    
     4   chain=input action=add-src-to-address-list protocol=icmp address-list=ICMP_SSH_98_stage1 address-list-timeout=1m in-interface=ether1 packet-size=98 
    
    



    Собственно здесь всё просто.

    Поехали дальше удаляем себя из адрес листов.


    Многие кто настраивают MikroTik используют защиту от перебора паролей Bruteforce wiki.mikrotik.com/wiki/Bruteforce_login_prevention
    Бывает сам отрубаю себе руки. Так что сейчас мы будем удалять себя из листов в которые мы могли попасть.
    И так используем наработки которые у нас были из прошлого примера изменим только конечный лист на plsdelme

    [admin@kirilka] /ip firewall filter> print
    Flags: X - disabled, I - invalid, D - dynamic 
     0   chain=input action=add-src-to-address-list protocol=icmp src-address-list=ICMP_SSH_128_stage1 address-list=plsdelme address-list-timeout=1m  in-interface=ether1 packet-size=128 
    
     1   chain=input action=add-src-to-address-list protocol=icmp src-address-list=ICMP_SSH_98_stage2 address-list=ICMP_SSH_128_stage1 address-list-timeout=1m  in-interface=ether1 packet-size=128 
    
     2   chain=input action=add-src-to-address-list protocol=icmp src-address-list=ICMP_SSH_98_stage1 address-list=ICMP_SSH_98_stage2 address-list-timeout=1m in-interface=ether1 packet-size=98 
    
     3   chain=input action=add-src-to-address-list protocol=icmp address-list=ICMP_SSH_98_stage1 address-list-timeout=1m in-interface=ether1 packet-size=98 
    
    

    Так же нам понадобиться скрипт следующего содержания:
    :local wlist "plsdelme";
    :local tmp "";
    :local tmp1 "";
    
     :if ( [/ip firewall address-list find ] != "") do={
      :foreach i in [/ip firewall address-list find list=$wlist] do={
        :set tmp [/ip firewall address-list get $i address];
    		:foreach x in [/ip firewall address-list find list~"blacklist"] do={
    			:set tmp1 [/ip firewall address-list get $x address];
    			:if ( $tmp1 = $tmp) do={
    				/ip firewall address-list remove $x;
    			}
    			}
    		}
    }
    

    Данный скрипт необходимо поместить в cron scheduler c интервалом меньшим чем время но которое мы добавляем адрес в лист plsdelme
    Что делает сприпт?
    Он ищет адреса в листах plsdelme и сверяет значения с листами ~«blacklist», если есть совпадение то удаляет эту запись.

    Если вы немного модифицируете скрипт, то можно делать в принципе всё что угодно.
    Хотя для этих целей, больше подойдёт использование API.
    • +18
    • 29.6k
    • 9
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 9

      0
      Спасибо, хотел реализовать подобное.

      P.S.
      Пост прочитал бегло, поэтому вот:
      для себя хотел сделать блокировку перечисленных портов извне, а если начать пинговать хитрым образом или ломиться на некий порт 2-3 раза (нужное количество раз), то необходимые порты откроются для IP инициатора.
      Вот хочется спросить, можно ли такое сделать, не считаю теории, где можно сделать многое.
        0
        В первом примере это и реализовано, только через ICMP
        +1
        Позанудствую.
        Port knocking все таки.
          0
          Спасибо поправил
          0
          Спасибо за статью.
          Не перестаю удивлятся возможностям микротиков!
            0
            Так как статья выпадает первой по запросам в гугле типа «icmp port knocking микротик» считаю необходимым добавить следующее:
            при использовании стандартного файерволла, в котором вверху присутствует правило

            add action=accept chain=input comment=«defconf: accept established,related,untracked» connection-state=established,related,untracked

            приведенные в статье примеры работать не будут. Причина — при прохождении первого icmp пакета стейтфул файервол микротика создает запись в Connections на 10 секунд. Соответственно, в течение этого времени icmp пакеты с сорс ip будут проходить файерволл по этому самому правилу, т.к. connection-state=established. До добавленных правил просто дело не доходит. И чтобы примеры заработали нужно или 11 секунд между пингами, чтобы запись в Connections удалилась (но это сильно растягивает время выполнения скрипта на клиенте), либо нужно добавить в первое правило исключение для icmp:

            add action=accept chain=input comment=«defconf: accept established,related,untracked» connection-state=established,related,untracked protocol=!icmp
              0

              Почти 6 лет прошло.
              Вы правы, но вы всегда должны самостоятельно для себя определить как вы должны использовать файрвол, кто-то вообще не включает Connection-tracker.
              здесь же вселишь идея и её реализация, без каких либо уточнений.

                0
                Кирилл, для Вас, как для гуру (это без сарказма) конечно же всё и так понятно. Я же Вас подправил не подколки ради, а лишь потому что статья действительно появляется в выдаче по указанным ключевым словам одной из первых. А кто чаще всего читает статьи по выдаче? Правильно, новички. Не имеющие Вашего опыта. Начинающие настройку не с blank, как Вы, а с default. Даже, возможно, пока не знающие, что такое conntrack и где его включать/выключать. Тема кнокинга всё чаще востребована в связи с нарастанием агрессивности интернета как среды. А раз статья так высоко в выдаче — полагаю, будет дальновидно её актуализировать. Например, с учетом оптимизации производительности (так хорошо раскрытой Вами на московском MUM2018): вынести обработку кнокинга в отдельную цепочку, в правилах внутри которой отключить проверки на протокол, оставить только размер пакетов и/или пайлоад. И т.д. Еще раз — мой респект вашему опыту и компетенции.
                  0

                  Так и я без претензий =)

            Only users with full accounts can post comments. Log in, please.