Открыть порт ssh по стуку с IPtables в Unix/Linux

Открыть порт ssh по стуку с IPtables в Unix/Linux

Одно из очень простых решений — открывать ssh порт ( стандартный 22-й порт) после того как постучишься в заданный, «высокий» порт.

Открыть порт ssh по стуку с IPtables в Unix/Linux

Есть несколько способов сделать стук, чтобы открылся нужный порт. Сейчас я расскажу о нескольких из них.

-===Способ 1 (самый простой), стук на 1 порт===-

И так, я сейчас выполню ряд действий с IPtables. И так, первое что необходимо сделать — это создать новую цепочку чтобы выполнять проверку на попытки соединенится на защищаемый порт:

# iptables -N ssh_knock

Далее, чтобы не ломились на определенный порт, я сейчас задам правило. Суть заключается в следующем, если кто-то будет производить стук на порт более 2-х раз за одну минуту ( 60 секунд), попадает в бан:

# iptables -A ssh_knock -m recent --rcheck --seconds 60 --hitcount 2 -j RETURN

Следующим правилом создается исключение, которое говорит

Если производился стук в нужный порт ( за последние 10 секунд), то разрешаем соединение:

# iptables -A ssh_knock -m recent --rcheck --seconds 10 -j ACCEPT

Очистим  INPUT цепочку:

# iptables -F INPUT

Разрешаем прохождение пакетов на установленные соединения:

# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Все попытки открыть новое SSH соединение, будут проверяться:

# iptables -A INPUT -m state --state NEW -p tcp --dport 22 -j ssh_knock

Сейчас, собственно  прописываем правило для стука на заданный порт:

# iptables -A INPUT -m state --state NEW -p tcp --dport 27520 -m recent --set

Закрываем соседние порты ( чтобы не стучались):

# iptables -A INPUT -m state --state NEW -p tcp -m multiport --dport 27519,27521 -m recent --remove

Остальное, запретим:

# iptables -P INPUT DROP

Для удобства использования, я создал баш скрипт:

# vim knock.sh

И прописал в него:

#/bin/sh -x

iptables -N ssh_knock
iptables -A ssh_knock -m recent --rcheck --seconds 60 --hitcount 2 -j RETURN
iptables -A ssh_knock -m recent --rcheck --seconds 30 -j ACCEPT
iptables -F INPUT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m state --state NEW -p tcp --dport 22 -j ssh_knock
iptables -A INPUT -m state --state NEW -p tcp --dport 27520 -m recent --set
iptables -A INPUT -m state --state NEW -p tcp -m multiport --dport 27519,27521 -m recent --remove
iptables -P INPUT DROP

Запускаем:

$ bash knock.sh

PS: Может понадобится выставить права на исполнение ( chmod +x knock.sh).

Выполним проверку iptables:

[root@localhost ~]# iptables -L -n
Chain INPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED 
ssh_knock  tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22 
           tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:27520 recent: SET name: DEFAULT side: source 
           tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW multiport dports 27519,27521 recent: REMOVE name: DEFAULT side: source 

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited 

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain ssh_knock (1 references)
target     prot opt source               destination         
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           recent: CHECK seconds: 60 hit_count: 2 name: DEFAULT side: source 
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           recent: CHECK seconds: 30 name: DEFAULT side: source 
[root@localhost ~]#

Реализация довольно простая, но на практике — выполняем защиту: После стука на 27520 порт, будет производиться открытие SSH порта ( в этом примере, 22-й порт используется). Если за минуту будет произведено более 1 стука, порт не будет открыт и вы получите бан. Соседние порты были закрыты с целью защиты и от предотвращения подбора стука.

Чтобы постучаться, используем команду:

$ nmap -Pn --host_timeout 201 --max-retries 0 -p 27520 192.168.13.157

PS: Можно заюзать любую другую тулзу — telnet, nc hping.

И после чего, выполняем подключение на сервер:

$ ssh captain@192.168.13.157 -p22

Так не есть удобно! По этому, создаем баш-скрипт:

# vim knock_ssh_connection.sh

И прописывам в него:

#!/bin/sh -x

nmap -Pn --host_timeout 201 --max-retries 0 -p 27520 192.168.13.157 &>2 >>/dev/null
ssh captain@192.168.13.157 -p22

Надеюсь описывать не нужно что делает данный скрипт? -Если что, пишите в коменты, отвечу и помогу.

PS: Не забываем выставить права на использование (chmod +x knock_ssh_connection.sh).

А сейчас я, расскажу более сложный стук, с использованием 3-х стуков на разные порты.

-===Способ 2 (более продвинутый, сложный), стук на 3 порта===-

Можно сохранить любое количество отдельных именованных списков. В этом случае будет три:

  • KNOCK1 — идентифицирует исходные адреса, которые выполнили первый стук ( но не второй или третий).
  • KNOCK2 — определяет адреса источника, которые выполнили первый и второй стук ( но не третий).
  • KNOCK3 — идентифицирует исходные адреса, которые выполнили первый, второй и третий стуки ( но еще не установили соединение).

Т.е, чтобы подключиться на 22-й SSH порт, нужно постучаться на 3 разных порта, и после чего выполнить подключение на сервер.

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

Как и в случае с большинством конфигураций брандмауэра, после принятия решения о принятии первого пакета соединения все дальнейшие пакеты, входящие в одно и то же соединение, должны проходить беспрепятственно:

# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Обычно, нецелесообразно блокировать трафик с интерфейса loopback, по этому, создаем правило:

# iptables -A INPUT -s 127.0.0.0/8 -j ACCEPT

Блокировка ICMP-трафика может обеспечить некоторые незначительные преимущества в безопасности, но в большинстве случаев она может причинить больше неудобств, по этому, не блокируем его, а разрешаем прохождение ICMP пакетов:

# iptables -A INPUT -p icmp -j ACCEPT

Разрешаем прохождения трафика на порту 80:

# iptables -A INPUT -p tcp --dport 80 -j ACCEPT

Когда сервер ожидает первый стук:

  • Если пакет является первым стуком, то переход в состояние 1 (STATE 1);
  • Иначе остаются в состоянии 0 (STATE 0).
  • В любом случае, любой полученный трафик должен быть удален.
# iptables -N STATE0
# iptables -A STATE0 -p udp --dport 12345 -m recent --name KNOCK1 --set -j DROP
# iptables -A STATE0 -j DROP

Когда первый удар получен, и сервер ждет второго удара:

  • Если пакет является вторым стуком, то переходом в состояние 2 (STATE 2);
  • Если пакет является еще первым стуком, то остаемся в состоянии 1 (STATE 1);
  • В противном случае выполните возврат к состоянию 0 (STATE 0).
  • Как и выше, любой полученный трафик должен быть удален.

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

# iptables -N STATE1
# iptables -A STATE1 -m recent --name KNOCK1 --remove
# iptables -A STATE1 -p udp --dport 23456 -m recent --name KNOCK2 --set -j DROP
# iptables -A STATE1 -j STATE0

Когда первый и второй удары были получены, и сервер ожидает третий стук:

  • Если пакет является третьим ударом, то переход в состояние 3 (STATE 3);
  • Если пакет является первым стуком, то регресс переходит в состояние 1 (STATE 1);
  • В противном случае выполните возврат к состоянию 0 (STATE 0).
  • Как и выше, любой полученный трафик должен быть удален.
# iptables -N STATE2
# iptables -A STATE2 -m recent --name KNOCK2 --remove
# iptables -A STATE2 -p udp --dport 34567 -m recent --name KNOCK3 --set -j DROP
# iptables -A STATE2 -j STATE0

Когда все три удара были получены, и сервер ожидает соединения:

  • Если пакет является началом входящего TCP-соединения с соответствующим портом, то принимайте его;
  • Если пакет является первым стуком, то регресс переходит в состояние 1 (STATE 1);
  • В противном случае выполните возврат к состоянию 0 (STATE 0).
  • Необходимо только принять первый пакет соединения таким образом, потому что уже существует правило принимать трафик, который является частью установленного соединения. Как и выше, другой трафик следует отбросить.
# iptables -N STATE3
# iptables -A STATE3 -m recent --name KNOCK3 --remove
# iptables -A STATE3 -p tcp --dport 22 -j ACCEPT
# iptables -A STATE3 -j STATE0

Определив цепи обработчика для всех четырех состояний (3 стука + подключение), необходимо поместить правила во входящую цепочку, чтобы вызвать соответствующую цепочку обработчика. Это можно сделать, проверив, находится ли адрес источника текущего пакета в любом из трех списков:

# iptables -A INPUT -m recent --name KNOCK3 --rcheck -j STATE3
# iptables -A INPUT -m recent --name KNOCK2 --rcheck -j STATE2
# iptables -A INPUT -m recent --name KNOCK1 --rcheck -j STATE1
# iptables -A INPUT -j STATE0

И так. Я все рассказал, но для удобства, я вынесу все эти правила в отдельный bash-скрипт:

# vim 3_knocking_ssh_connect.sh

И вставляем его:

#!/bin/sh -x

iptables -F
iptables -X
iptables -Z

iptables -N STATE0
iptables -A STATE0 -p udp --dport 12345 -m recent --name KNOCK1 --set -j DROP
iptables -A STATE0 -j DROP

iptables -N STATE1
iptables -A STATE1 -m recent --name KNOCK1 --remove
iptables -A STATE1 -p udp --dport 23456 -m recent --name KNOCK2 --set -j DROP
iptables -A STATE1 -j STATE0

iptables -N STATE2
iptables -A STATE2 -m recent --name KNOCK2 --remove
iptables -A STATE2 -p udp --dport 34567 -m recent --name KNOCK3 --set -j DROP
iptables -A STATE2 -j STATE0

iptables -N STATE3
iptables -A STATE3 -m recent --name KNOCK3 --remove
iptables -A STATE3 -p tcp --dport 22 -j ACCEPT
iptables -A STATE3 -j STATE0

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -s 127.0.0.0/8 -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

iptables -A INPUT -m recent --name KNOCK3 --rcheck -j STATE3
iptables -A INPUT -m recent --name KNOCK2 --rcheck -j STATE2
iptables -A INPUT -m recent --name KNOCK1 --rcheck -j STATE1
iptables -A INPUT -j STATE0

Ну, переходим к тестированию!

Теперь чтобы выполнить подключение (я создам скрипт для подключение), открываем файл:

# vim knock_ssh_connection.sh

И прописывам в него:

#!/bin/sh

nmap -Pn --host_timeout 201 --max-retries 0 -p 12345 192.168.13.157 &>2 >>/dev/null
nmap -Pn --host_timeout 201 --max-retries 0 -p 23456 192.168.13.157 &>2 >>/dev/null
nmap -Pn --host_timeout 201 --max-retries 0 -p 34567 192.168.13.157 &>2 >>/dev/null
ssh captain@192.168.13.157 -p22

Вот и все.

Можно использовать еще один метод подключения:

$ for x in 12345 23456 34567; do nmap -Pn --host_timeout 201 --max-retries 0 -p $x 192.168.13.157 && sleep 1; done && ssh captain@192.168.13.157

Используем на здоровье.

Хотел бы отметить следующее, уже имеется готовое решение  — knockd. Но о нем я расскажу немного позже.

На этом у меня все, статья «Открыть порт ssh по стуку с IPtables в Unix/Linux» завершена.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.