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-соединений