Comments 66
Отличная статья, с удовольствием прочитал ее дважды :)
А если серьезно, то реально попробую эту технику использовать
порт-кнокинг имхо гораздо надежнее. без ключа не открыт ни один лишний порт, и одного лишнего движения.
есть еще пинг-кнокинг под некоторые системы прощее стучатся получается.
Вот не понимаю, зачем.
Вам шашечки или ехать?
У вас цель: обезопасить сервер или сделать мир лучше?
У меня, как правило, первая.
Поэтому sshd + blacklistd + ipfw ОТЛИЧНО справляются с данной задачей (по опыту, куда лучше fail2ban и sshguard).
И порт не меняю: а смысл?
Из-за того, что кто-то куда-то может пару раз постучать, корячиться и всегда помнить, что при ssh — одним способом порт указывать, при scp — другим?.. А скрипты: когда в одном проекте один порт, а в другом — он занят приложением?..
Безопасности добавли на ноль целых и ничего десятых, зато неудобства — на все 100 :)
Для желающих тут же погрузиться в поиск: blacklistd хорош, но FreeBSD-only. Ждём, как говорится, e-buildов
по опыту, куда лучше fail2ban и sshguard
Аргументировано.
На собственном опыте могу сказать, что "по опыту" как правило значит чуть более чем ничего. Кхе… кхе :)
На самом деле главный аргумент приспешников blacklistd ("не нужно парсить лог") "разбивается" единственным примером:
Демон sshd (при включенном UseBlacklist) отправит инфу (authentication success/failure) на blacklistd сокет, и… запишет это в лог. Ну а blacklistd прочитает её из сокета и распарсит.
Чем оно в принципе отличается от "распарсивания" fail2ban тех же строчек прочитанных из лога, никто так и не смог мне внятно объяснить.
Кроме того, fail2ban тоже это давно умеет, а в новых версиях уже официальным протоколом и для сообщения об отдельных неудачных попытках, т.е. достаточно отправить ему на сокет:
# отовсюду (симулируем простейший "маринад"):
f2b_attempt_msg="(lp0\nS'set'\np1\naS'%s'\np2\naS'attempt'\np3\naS'%s'\np4\na.<F2B_END_COMMAND><F2B_CLOSE_COMMAND>"
printf "$f2b_attempt_msg" sshd 192.0.2.1 | nc -q 0 -U '/run/fail2ban/fail2ban.sock'
# из питона:
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM);
s.connect('/run/fail2ban/fail2ban.sock');
s.send(pickle.dumps(['set', 'sshd', 'attempt', '192.0.2.2', 'unknown user'], 0) + b"<F2B_END_COMMAND>"); s.close()
# ну и из шела:
fail2ban-client set <jail> attempt <IP> [<failure-message1> ... <failure-messageN>]
Демон sshd (при включенном UseBlacklist) отправит инфу (authentication success/failure) на blacklistd сокет, и… запишет это в лог.
настраиваемо.
Ну а blacklistd прочитает её из сокета и распарсит.
Чем оно в принципе отличается от "распарсивания" fail2ban тех же строчек прочитанных из лога, никто так и не смог мне внятно объяснить.
лучше уж хотя бы тем, что не нужно в системе держать питон ради единственного fail2ban.
размер используемой памяти — очевидно же, не в пользу fail2ban.
и решение в случае sshd+blacklistd+ipfw получается "искаропки".
Менять порт рекомендуют наряду с другими мероприятиями по усилению безопасности
можете привести пример такой рекомендации? просто стало интересно где так рекомендуют
отправляет бесконечный поток случайно сгенерированных данных
А как же стоимость исходящего трафика?
Это не сделает мир лучше прямо сразу, но при относительно массовом применении намного увеличит порог вхождения как для реальных жуликов, так и для бестолковых пионэров с кривыми ручками. И реально сократит мусорный трафик.
Опять же, можно написать (уже написано примерно во времена появления TARPIT в iptables, но гуглить лень) генератор пакетов, который навешает у вас TARPIT соединений, которые вы сами же будете поддерживать и забивать свой контрэк, а со стороны хакера это не будут соединения, а просто пара пакетов с железяки, которая даже не знает что такое TCP.
Решение есть: на все порты, которые -j TARPIT делать еще -t raw -j NOTRACK (ну или совсем отказаться от conntrack)
Но такие сложности уже напоминают ситуацию — обе стороны наелись
Но все же в целом с вами соглашусь: использовать -j TARPIT, если уж хочется именно потроллить ботнеты (ведь сканят именно ботнеты, вручную мало что сканят), куда практичнее, чем запускать демона на питоне или даже С, симулирующего ssh
А ещё лучше запретить вход с паролем, и вообще думать забыть о потенциальных "взломщиках".
В результате, 6 из 7 подключений отваливаются через 30 секунд, седьмое протянулось на 17 минут и 30 секунд.
Дословный ответ: Наша система работает отлично, а вам не надо подключатся через VPN к нашему сайту.
Ответ от других еще более глобален:

INPUT DROP
.Правильнее
-A INPUT -p tcp -m tcp -j REJECT --reject-with tcp-reset
-A INPUT -p udp -m udp -j REJECT --reject-with icmp-port-unreachable
Так это выглядит закрытыми (не открытыми приложениями) портами, и в скане nmap, к примеру, порты будут 'closed', а не 'FILTERED'.
Когда кто-то обращается к хосту на порт, который не «слушает» ни одно приложение (порт closed), он (хост) отвечает ICMP-сообщением «icmp-port-unreachable» («Порт недоступен»). Если недоступен весь хост, то предыдущий роутер отправляет icmp-host-unreachable («Узел недоступен»).
Т. е. при нормальном функционировании сети пакеты не должны пропадать «в никуда» и бесследно. Таким образом, отсутствие ответа (и, к примеру, «повисшая» в стадии установки соединения TCP-сессия, как в примере) как раз говорит о фильтрации, и именно так и показывает это nmap. О чём прямо написано в «man nmap»:
«The state is either open, filtered, closed, or unfiltered. Open means that an application on the target machine is listening for connections/packets on that port. Filtered means that a firewall, filter, or other network obstacle is blocking the port so that Nmap cannot tell whether it is open or closed. Closed ports have no application listening on them… »
Так что, прежде чем что-то безапелляционно утверждать, — проверяйте себя.
INPUT DROP
, то атакующий видит FILTERED
для всех портов, вне зависимости от того, открыт порт или нет. Используя REJECT
, атакующий видит то же самое, только вместо FILTERED
, отображается CLOSED
. Однако есть проблема: REJECT
, в отличии от DROP
, не обрывает соединение, а всё же отвечает на запрос.Учитывая то, что ни в одном из этих случаев атакующий не может знать, используется тот или иной порт на целевой машине, то правильнее всего использовать
DROP
, а не заставить машину отвечать на ненужные запросы.Беглый поиск не дал результата.
> И там же приписка: «Сервер МОЖЕТ послать другие строки данных перед отправкой строки с версией». И нет ограничения на объём этих данных, просто каждую строку нужно начинать с SSH-.
По поводу начала строки RFC говорит прямо противоположное: The server MAY send other lines of data before sending the version string. Each line SHOULD be terminated by a Carriage Return and Line Feed. Such lines MUST NOT begin with «SSH-»
> Именно этим занимается программа Endlessh: она отправляет бесконечный поток ..., а каждая строка начинается с SSH-
Чтобы убедиться что это не так достаточно сделать telnet localhost 2222
Или посмотреть в исходник.
static int
randline(char *line, int maxlen, unsigned long s[1])
{
int len = 3 + rand16(s) % (maxlen - 2);
for (int i = 0; i < len - 2; i++)
line[i] = 32 + rand16(s) % 95;
line[len - 2] = 13;
line[len - 1] = 10;
if (memcmp(line, "SSH-", 4) == 0)
line[0] = 'X';
return len;
}
</code>
Странно, что никто этого не заметил.
if (memcmp(line, "SSH-", 4) == 0)
не проверяет, что строка начинается с «SSH-» и если да, то line[0] = 'X';
заменяет первый символ на «X»? То есть, такая строка становится «XSH-».
Ловушка (тарпит) для входящих SSH-соединений