Открыть порт 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» завершена.