среда, 22 апреля 2020 г.

Закрываем доступ к терминальному серверу с помощью iptables

По данным на конец марта, с февраля количество RDP-серверов в интернете выросло на 9-21%. То есть, людей выгнали на удаленку и пооткрывали доступ через инет. И все бы ничего, но при этом также активизировались боты, сканируещие интернет на предмет таких серверов и пытающихся брутфорсом пробраться на сервер. Хорошего мало, поскольку делов наделать могут даже и правами пользователя, а если уж с админскими правами влезут - туши свет, сливай масло.

Ну и я в один прекрасный день обнаружил на сервере постоянный аудит отказа.
Что это означает? То, что кто-то обнаружил порт, на котором висит RDP (кстати, нестандартный, это было первое, что я сделал) и брутфорсит. Естественно, сразу все бросил и начал смотреть - кто и откуда. Маршрутизатор у меня сделан на базе AltLinux Server p8, в нем есть система настройки alterator, но она регрессирует с каждым следующим выпуском, посему придется копать ручками.

Первый помошник - tcpdump, запускаем

tcpdump -n -i enp4s0 port 3389

и радостно наблюдаем веселый поток цифр. Надо бы отфильтровать...
Второй помошник - grep. Допустим, мой ip 10.2.3.5. Убираем его из вывода

tcpdump -n -i enp4s0 port 3389 | grep -v 10.2.3.5

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

tcpdump -n -i enp4s0 port 3389 | grep -v 10.2.3.

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

iptables --list-rules

Нас интересует цепочка INPUT, смотрим, вначале идут

-A INPUT -f -j DROP
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i enp4s0 -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -i enp4s0 -p udp -m udp --dport 80 -j ACCEPT
-A INPUT -i enp4s0 -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -i enp4s0 -p udp -m udp --dport 443 -j ACCEPT
-A INPUT -i enp4s0 -p tcp -m tcp --dport 3389 -j ACCEPT
-A INPUT -i enp4s0 -p udp -m udp --dport 3389 -j ACCEPT
-A INPUT -i enp4s0 -j DROP

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

по результатам просмотра tcpdump были выявлены 5 адресов, с которых ломились на сервер, надо их внести в список правил, причем не абы как, а вставить, начиная с третьей позиции

iptables -I INPUT 3 -s 213.109.81.190 -j DROP
iptables -I INPUT 3 -s 141.98.81.122 -j DROP
iptables -I INPUT 3 -s 78.128.113.2 -j DROP
iptables -I INPUT 3 -s 5.188.206.6 -j DROP
iptables -I INPUT 3 -s 138.99.216.143 -j DROP

повторяем tcpdump и наблюдаем следующую картину - запрос приходит, но до сервера не доходит, а значит, ответа нет.
Отлично, на скорую руку зловредов прижали.
Теперь начинаем размышлять. 
Alterator в альте сам управляет набором правил для iptables, его можно выключить и вручную прописывать каждое правило, но очень уж не хочется, слишком много телодвижений приходится делать для банального перенаправление портов. Посему принято решение "втиснуться" в естественный ход событий и хакнуть свой же сервер.

Задача. Обеспечить доступ по RDP для сотрудников, сидящих дома.
Решение. Нужны их айпишники.
Осложнения - у всех дома динамические апишники, выдаваемые провайдером на время. Но при этом все сидят через одного провайдера, а значит находятся внутри одной большой городской сети, которая имеет свой размер и вполне доступна для описания.

После небольших тестов был сделан следующий скрипт


#!/bin/sh

#список адресов, с которых разрешаем заходить на терминальный сервер

WHITEIP=(
101.84.0.0/16
101.121.0.0/16)
#порт терминального сервера
TERMPORT=3389
#что будем делать с неподходящими пакетами
ACTION=DROP # or REJECT
#сетевой интерфейс маршрутизатора, смотрящий в интернет
INTERFACE=enp4s0
#статический адрес маршрутизатора
INTERFACEIP=192.168.133.149/32 # of course this is not my really IP )))
#адрес сервера в локалке
MSTERMIP=192.168.0.200
echo DROP and LOG
iptables -I INPUT 3 -i ${INTERFACE} -p udp -m udp --dport ${TERMPORT} -j ${ACTION}
iptables -I INPUT 3 -i ${INTERFACE} -p tcp -m tcp --dport ${TERMPORT} -j ${ACTION}
echo ACCEPT white ip's
for IPs in "${WHITEIP[@]}"
do
  iptables -I INPUT 3 -i ${INTERFACE} -p udp -m udp -s ${IPs} --dport ${TERMPORT} -j ACCEPT
  iptables -I INPUT 3 -i ${INTERFACE} -p tcp -m tcp -s ${IPs} --dport ${TERMPORT} -j ACCEPT
done
echo PREROUTING
for IPs in "${WHITEIP[@]}"
do
  iptables -t nat -A PREROUTING -d ${INTERFACEIP} -s ${IPs} -p tcp -m tcp --dport ${TERMPORT} -j DNAT --to-destination ${MSTERMIP}:${TERMPORT}
done
echo OUTPUT
iptables -t nat -A OUTPUT -d ${INTERFACEIP} -p tcp -m tcp --dport ${TERMPORT} -j DNAT --to-destination ${MSTERMIP}:${TERMPORT}
echo FORWARD
iptables -I FORWARD 3 -d ${MSTERMIP} -p tcp -m tcp --dport ${TERMPORT} -j  ACCEPT


Итак, что мы здесь делаем?
Перво-наперво, описываем переменные, если что-то надо менять - это удобно.
Далее, начинаем вставлять в цепочку INPUT в третью позицию. Для начала мы дропаем все tcp и udp пакеты пришедшие на внешний интерфейс. Далее в цикле по списку разрешенных адресов включаем прием для каждого разрешенного ip или целой подсети на rdp-порт.

Казалось бы - сначала надо разрешить, а потом запрещать? Ведь логика iptables именно такая!
Да! Но каждая вставка в определенную позицию смещает эту позицию вниз и в результате просле прохода цикла первыми оказываются разрешительные команды, которые бьют более точно - конкретный ip на конкретный порт.
"А-а-а-а.... Вон оно чё, Михалыч.... А мужики-то не знают... "(с) )))))))

ну и дальше собственно делаем проброс порта в таблице NAT
и напоследок разрешаем ответ сервера по rdp-порту.

После всех манипуляций осталось втиснуть этот скрипт в стандартную систему запуска правил. После каждой перезагрузки правил iptables нет и система загружает их из конфигурационных файлов альтератора. Мне было кисло их изучать, поэтому этот скрипт был сохранен как /etc/net/netup-post и сделан исполняемым. Это стандарный пост-скрипт, выполняющийся после запуска сетевой подсистемы и после отрабатывания альтератора. Удостоверится, что все работает, можно без перезагрузки сервера, просто выполним service network restart и затем просморим iptables --list-rules.

-A INPUT -f -j DROP
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -s 101.84.0.0/16 -i enp4s0 -p tcp -m tcp --dport 3389 -j ACCEPT
-A INPUT -s 101.84.0.0/16 -i enp4s0 -p udp -m udp --dport 3389 -j ACCEPT
-A INPUT -s 101.121.0.0/16 -i enp4s0 -p tcp -m tcp --dport 3389 -j ACCEPT
-A INPUT -s 101.121.0.0/16 -i enp4s0 -p udp -m udp --dport 3389 -j ACCEPT
-A INPUT -i enp4s0 -p tcp -m tcp --dport 3389 -j DROP 
-A INPUT -i enp4s0 -p udp -m udp --dport 3389 -j DROP 
-A INPUT -i enp4s0 -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -i enp4s0 -p udp -m udp --dport 80 -j ACCEPT
-A INPUT -i enp4s0 -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -i enp4s0 -p udp -m udp --dport 443 -j ACCEPT
-A INPUT -i enp4s0 -j DROP

Все как и ожидалось - первые два правила - отброс фрагментов  и разрешение уже установленных соединений, а дальше пошли наши вставочки. Ну и просмотр tcpdump показывает, что запросы от зловредов приходят, но в ответ им ничего не обламывается. Да и на терминальном сервере тишина - туда доходят только разрешенные коннекты.




Комментариев нет:

Отправить комментарий