При реализации стучалки я отталкивался от таких условий:
iptables
.
Неохота что-то устанавливать, настраивать, обновлять,
держать всегда поднятым.Итого, какие я избрал правила стука:
DROP
,
а REJECT
. Чтобы клиенты не пытались соединиться повторно.Таким образом, клиент должен выполнить N-1 попытку
подключения, на которые он гарантированно получит
REJECT
. Большинство ботов сдаются после одной-трёх попыток.
Потом клиенту предоставляется только одна попытка подключиться.
Если он не угадал пароль, то новая серия попыток будет доступна
только по истечении некоторого времени.
Вызываем port-knocking цепочку в подходящем месте как-то так.
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j KNOCK
Не забываем, что в цепочку для стука должны попадать только SYN-пакеты.
Правила цепочки очень просты:
# создаём или обновляем запись в /proc/net/xt_recent/KNOCK_SSH
-A KNOCK -m recent --set --name KNOCK_SSH --rsource
# если за последние 60 секунд было более 10 попыток подключиться, то не пропускаем попытку
-A KNOCK -m recent --rcheck --seconds 60 --hitcount 11 --name KNOCK_SSH --rsource -j RETURN
# если за последние 60 секунд это попытка 10-я пропускаем подключение
-A KNOCK -m recent --rcheck --seconds 60 --hitcount 10 --name KNOCK_SSH --rsource -j ACCEPT
# в противном случае возвращаемся из цепочки
Внимание! Я предполагаю, что основная цепочка правил закрытая. То есть возврат из цепочки равносилен запрету входа.
Ну и не забудьте:
iptables -N KNOCK
А то будете иметь
iptables: No chain/target/match by that name.
Первые 10 попыток подключиться будут безуспешными. Это отвадит большинство сканеров.
Если в порт стучат реже 10 раз в минуту, то у сканера не будет возможности подключиться.
Если в порт стучат чаще 10 раз в минуту, то у сканера будет только одна попытка. Для подбора пароля этого недостаточно.
Теоретически, сканер может стучаться ровно 10 раз в минуту, тогда он сможет выполнять проверку пароля раз в 6 секунд. Я считаю, что этого тоже недостаточно для успешной атаки.
Если ваша паранойя зашла дальше моей, то вы можете поменять цифры или
добавить таблицы (аналогичные KNOCK_SSH
)
и цепочки (аналогичные KNOCK
).
Таким образом можно собрать сколь угодно сложную (в разумных пределах)
машину состояний. Правда, при этом уже придётся помнить правильный «стук».
Я считаю это слишком обременительным.
И ещё одно замечание: не ставьте hitcount больше 20,
подробнее смотрите man iptables
.
# фаервол закрыт
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
# дополнительные цепочки для удобства
:KNOCK - [0:0]
:TCP - [0:0]
:TRUSTED - [0:0]
# пропускаем всё для установленных соединений
# (далее будет только обработка новых соединений)
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# пропускаем всё, что относится к локальному хосту
-A INPUT -i lo -j ACCEPT
# игнорируем весь сломанный трафик
-A INPUT -m state --state INVALID -j DROP
# пропускаем всё с доверенных IP
-A INPUT -j TRUSTED
# обрабатываем разные виды трафика (есть только TCP, но можно завести для чего угодно)
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j TCP
-A INPUT -p icmp -j ACCEPT
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
# цепочка для обработки tcp
# 22 порт отправляем на анализ стука
-A TCP -p tcp -m tcp --dport 22 -j KNOCK
# торенты пропускаем
-A TCP -p tcp -m tcp --dport 6881:6889 -j ACCEPT
# цепочки для анализа стука
-A KNOCK -m recent --set --name KNOCK_SSH --rsource
-A KNOCK -m recent --rcheck --seconds 60 --hitcount 11 --name KNOCK_SSH --rsource -j RETURN
-A KNOCK -m recent --rcheck --seconds 60 --hitcount 10 --name KNOCK_SSH --rsource -j ACCEPT
# доверенные IP-адреса, пропускаемые без фильтрации
-A TRUSTED -s 194.67.3.229/32 -j ACCEPT
Посмотреть только инициализации соединений:
tcpdump 'tcp[tcpflags] & tcp-syn != 0'
Посмотреть запомненные IP можно здесь /proc/net/xt_recent/KNOCK_SSH
.
Вы всегда можете добавить протоколирование в любое место. В этом
нет ничего сложного. Но дополнительным удобным местом для мониторинга
является файл /proc/net/xt_recent/KNOCK_SSH
.
Единственное, что надо помнить, что время там указывается в jiffies
.
jiffies
— это uptime, выраженный в CONFIG_HZ
. CONFIG_HZ
задаётся при сборке ядра и в большинстве случаев равна
1000. То есть один тик jiffies
равен 1/1000 секунды.
Некоторые системы собраны с CONFIG_HZ=100
.
Для просмотра информации из xt_recent
можно использовать
какой-нибудь такой скрипт:
perl -e '
@h = sort {$b->[0] <=> $a->[0]}
map {m-src=(\S+).*last_seen:\s(\S+)-; [$2, $1]} <>;
$m = $h[0][0];
print join("\n",
map {sprintf("%6.2f %s", @$_)}
grep {$_->[0] < 30}
map {[($m - $_->[0])/1000/60/60, $_->[1]]} @h) . "\n";
' /proc/net/xt_recent/KNOCK_SSH
Он читает IP-адреса и даты последних обращений, пересчитывает даты в часы, сортирует от настоящего в прошлое, оставляет только последние 30 часов, форматирует и выводит. Отредактируйте по вкусу.