Не секрет, что интернет — очень враждебная среда. Как только вы поднимаете сервер, он мгновенно подвергается массированным атакам и множественным сканированиям. На примере ханипота от безопасников можно оценить масштаб этого мусорного трафика. Фактически, на среднем сервере 99% трафика может быть вредоносным.

Tarpit — это порт-ловушка, который используется для замедления входящих соединений. Если сторонняя система подключается к этому порту, то быстро закрыть соединение не получится. Ей придётся тратить свои системные ресурсы и ждать, пока соединение не прервётся по таймауту, или вручную разрывать его.

Чаще всего тарпиты применяют для защиты. Технику впервые разработали для защиты от компьютерных червей. А сейчас её можно использовать, чтобы испортить жизнь спамерам и исследователям, которые занимаются широким сканированием всех IP-адресов подряд (примеры на Хабре: Австрия, Украина).

Одному из сисадминов по имени Крис Веллонс, видимо, надоело наблюдать за этим безобразием — и он написал маленькую программку Endlessh, тарпит для SSH, замедляющий входящие соединения. Программа открывает порт (по умолчанию для тестирования указан порт 2222) и притворяется SSH-сервером, а на самом деле устанавливает бесконечное соединение с входящим клиентом, пока тот не сдастся. Это может продолжаться несколько дней или больше, пока клиент не отвалится.

Установка утилиты:

$ make
$ ./endlessh &
$ ssh -p2222 localhost

Правильно реализованный тарпит отнимет у злоумышленника больше ресурсов, чем у вас. Но дело даже не в ресурсах. Автор пишет, что программа вызывает привыкание. Прямо сейчас в его ловушке 27 клиентов, некоторые из них подключены в течение недель. На пике активности в ловушке сидели 1378 клиентов в течение 20 часов!

В рабочем режиме сервер Endlessh нужно ставить на обычный порт 22, куда массово стучатся хулиганы. Стандартные рекомендации по безопасности всегда советуют переместить SSH на другой порт, что сразу на порядок сокращает размер логов.

Крис Веллонс говорит, что его программа эксплуатирует один абзац из спецификации RFC 4253 на протокол SSH. Немедленно после установления соединения TCP, но перед применением криптографии обе стороны должны послать идентификационную строку. И там же приписка: «Сервер МОЖЕТ послать другие строки данных перед отправкой строки с версией». И нет ограничения на объём этих данных, просто каждую строку нужно начинать с SSH-.

Именно этим занимается программа Endlessh: она отправляет бесконечный поток случайно сгенерированных данных, которые соответствуют RFC 4253, то есть отправка перед идентификацией, а каждая строка начинается с SSH- и не превышает 255 символов, включая символ окончания строки. В общем, всё по стандарту.

По умолчанию программа ожидает 10 секунд между отправками пакетов. Это предотвращает отключение по таймауту, так что клиент будет сидеть в ловушке вечно.

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

Автор постарался, чтобы утилита потребляла минимум ресурсов и работала абсолютно незаметно на машине. В отличие от современных антивирусов и других «систем безопасности», она не должна тормозить компьютер. Ему удалось минимизировать и трафик, и потребление памяти за счёт чуть более хитрой программной реализации. Если бы он просто запускал отдельный процесс на новое соединение, то потенциальные злоумышленники могли бы провести DDoS-атаку, открыв множество соединений для исчерпания ресурсов на машине. По одному потоку на соединение — тоже не лучший вариант, потому что ядро будет тратить ресурсы на управление потоками.

Поэтому Крис Веллонс выбрал для Endlessh самый легковесный вариант: однопоточный сервер poll(2), где клиенты в ловушке практически не потребляют лишних ресурсов, не считая объекта сокета в ядре и ещё 78 байт для отслеживания в Endlessh. Чтобы не выделять буферы получения и отправки для каждого клиента, Endlessh открывает сокет прямого доступа и напрямую транслирует пакеты TCP, игнорируя почти весь стек TCP/IP операционной системы. Входящий буфер вообще не нужен, потому что входящие данные нас не интересуют.

Автор говорит, что на момент своей программы не знал о существовании питоновского asycio и других тарпитов. Если бы он знал об asycio, то свою утилиту мог бы реализовать всего в 18-ти строчках на Python:

import asyncio
import random

async def handler(_reader, writer):
try:
while True:
await asyncio.sleep(10)
writer.write(b'%x\r\n' % random.randint(0, 2**32))
await writer.drain()
except ConnectionResetError:
pass

async def main():
server = await asyncio.start_server(handler, '0.0.0.0', 2222)
async with server:
await server.serve_forever()

asyncio.run(main())

Asyncio идеально подходит для написания тарпитов. Например, такая ловушка на много часов подвесит Firefox, Chrome или другого клиента, который пытается подключиться к вашему HTTP-серверу:

import asyncio
import random

async def handler(_reader, writer):
writer.write(b'HTTP/1.1 200 OK\r\n')
try:
while True:
await asyncio.sleep(5)
header = random.randint(0, 2**32)
value = random.randint(0, 2**32)
writer.write(b'X-%x: %x\r\n' % (header, value))
await writer.drain()
except ConnectionResetError:
pass

async def main():
server = await asyncio.start_server(handler, '0.0.0.0', 8080)
async with server:
await server.serve_forever()

asyncio.run(main())

Тарпит — отличный инструмент для наказания интернет-хулиганов. Правда, есть некоторый риск, наоборот, привлечь их внимание к необычному поведению конкретного сервера. Кто-то может подумать о мести и нацеленной DDoS-атаке на ваш IP. Впрочем, пока таких случаев не было, и тарпиты отлично работают.



Комментарии (49)


  1. AlexSpirit
    26.03.2019 10:00

    А текст вообще вычитывался перед публикацией? Или подразумевается, что до некоторых с первого раза не доходит? :-)


    1. lagudal
      26.03.2019 10:20

      я не глухой слепой, я не слепой. Поэтому не нужно мне повторять все по два раза, по два раза ))))


  1. FuzzyWorm
    26.03.2019 10:02
    +1

    Отличная статья, с удовольствием прочитал ее дважды :)
    А если серьезно, то реально попробую эту технику использовать


  1. vilgeforce
    26.03.2019 10:02

    Против ленивых хацкеров сработает, а неленивые доработают скрипты


  1. Cobolorum
    26.03.2019 10:07

    Вещь нужная, но не не питоне. То что автор ее на C написал позволит ее запустить даже на OpenWRT. Но еще лучше ее как модуль/правил в для примера в iptables. Как здесь ruunix.ru/597-tarpit-lovushka-v-iptables.html


    1. selivanov_pavel
      26.03.2019 23:01
      +1

      Добавлю для Ubuntu/Debian:

      sudo apt install xtables-addons-dkms
      iptables -t raw -A PREROUTING -p tcp --dport 22 -j NOTRACK
      iptables -A INPUT -p tcp --dport 22 -j TARPIT

      Понадобятся хедеры ядра и компилятор, если ещё не стоят.


  1. Mnemonik
    26.03.2019 10:22
    +1

    К сожалению вещь просто веселая (и классная), но никак не полезная. И никто не будет дорабатывать скрипты. Эти сканеры работают во-первых массово, во-вторых их цели ну настолько кривые устройства, где ssh сервера реализованы такими Ляо на коленке, весь этот сонм криво настроенного IoT, что среди них девайсов со странным поведением — 50%. Вообще никто не заметит что одно соединение кривое, их у сканера будут тысячи и сами по себе без специализированного тарпита через жопу.


  1. Fragster
    26.03.2019 11:21

    Port knocking, имхо, удобнее и безопаснее. К тому же дорабатывать нужно только скрипты клиентов.


    1. Anastasia_K
      26.03.2019 11:36

      ну о чём вы, какой port knocking? Конечно же лучше потратить десяток килобайт памяти спамера ценой отдельного сервиса у себя)


      1. pfg21
        27.03.2019 09:33

        т.е. тарпит не сервис, а что-то такое ангельское эфемерное, не заметное для системы… :) под ддосом весьма нехило может ресурсов пожрать.
        порт-кнокинг имхо гораздо надежнее. без ключа не открыт ни один лишний порт, и одного лишнего движения.

        есть еще пинг-кнокинг под некоторые системы прощее стучатся получается.


  1. begemoth3663
    26.03.2019 11:46
    +1

    Вот не понимаю, зачем.
    Вам шашечки или ехать?
    У вас цель: обезопасить сервер или сделать мир лучше?
    У меня, как правило, первая.
    Поэтому sshd + blacklistd + ipfw ОТЛИЧНО справляются с данной задачей (по опыту, куда лучше fail2ban и sshguard).
    И порт не меняю: а смысл?
    Из-за того, что кто-то куда-то может пару раз постучать, корячиться и всегда помнить, что при ssh — одним способом порт указывать, при scp — другим?.. А скрипты: когда в одном проекте один порт, а в другом — он занят приложением?..
    Безопасности добавли на ноль целых и ничего десятых, зато неудобства — на все 100 :)


    1. AnyKey80lvl
      26.03.2019 12:02

      Для желающих тут же погрузиться в поиск: blacklistd хорош, но FreeBSD-only. Ждём, как говорится, e-buildов


    1. sebres
      26.03.2019 14:48

      по опыту, куда лучше 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>]


      1. begemoth3663
        27.03.2019 10:25

        Демон sshd (при включенном UseBlacklist) отправит инфу (authentication success/failure) на blacklistd сокет, и… запишет это в лог.

        настраиваемо.


        Ну а blacklistd прочитает её из сокета и распарсит.
        Чем оно в принципе отличается от "распарсивания" fail2ban тех же строчек прочитанных из лога, никто так и не смог мне внятно объяснить.

        лучше уж хотя бы тем, что не нужно в системе держать питон ради единственного fail2ban.
        размер используемой памяти — очевидно же, не в пользу fail2ban.
        и решение в случае sshd+blacklistd+ipfw получается "искаропки".


        1. sebres
          27.03.2019 14:11

          "искаропки" оно было бы, если бы sshd умел всё то сам (это однако противоречило бы философии *nix).


    1. Berkof
      27.03.2019 06:26

      Сделать мир лучше — тоже неплохая цель, особенно если требует всего несколько килобайт на сервере.


      1. begemoth3663
        27.03.2019 11:12

        Это Вы так про питон пошутили? :)


        1. eirnym
          27.03.2019 23:15

          питон во многих сборках Linux есть по-умолчанию. Не во всех, естественно, но устанавливать специально его чаще всего не требуется.


  1. WebMonet
    26.03.2019 12:16

    отправляет бесконечный поток случайно сгенерированных данных

    А как же стоимость исходящего трафика?


    1. Antonto
      27.03.2019 00:22

      А там трафика и нет. 1 байт (1 пакет) в 10 секунд


  1. Inanity
    26.03.2019 13:09

    Подскажите, а какой смысл при работе Endlessh отправлять именно рандомные данные в строке с «SSH-»? Может быть можно ещё немного упростить программу?


    1. alexanster
      26.03.2019 13:41

      Чтоб враги сразу не догадались и заморочились поиском способа «расшифровки»?


      1. Inanity
        26.03.2019 13:59

        Так это до криптографии. Автор же писал, что можно отправлять любые данные до строки с версией. А просто так вещать не пойми кому свой рандом тоже не безопасно. Если генератор некачественный, то со стороны противника можно осуществлять анализ и это теоретически поспособствует другому вектору атак.


        1. alexanster
          26.03.2019 14:15

          Я ж не просто так взял в кавычки, я имел в виду: пускай потенциальный взломщик сидит и ломает голову, что же это такое, тратит ресурсы и время. А реальную криптографию даже в виду не имел.


        1. Cenzo
          27.03.2019 04:48

          Лучше как раз взять самый некачественный программный псевдогенератор (PRNG(x)), и пусть хоть сколько ломают себе голову. Потому как в системе и openssl используются совсем другие.


  1. barbos6
    26.03.2019 14:51
    +1

    59348 2465K TARPIT tcp — eth0 * 0.0.0.0/0 0.0.0.0/0 tcp multiport dports 20,22,25,80,135,139,5900,8080,8443 -j TARPIT --tarpit

    Это не сделает мир лучше прямо сразу, но при относительно массовом применении намного увеличит порог вхождения как для реальных жуликов, так и для бестолковых пионэров с кривыми ручками. И реально сократит мусорный трафик.


    1. trublast
      26.03.2019 19:30
      +1

      С одной стороны да, а с другой — тарпнутые (пойманные в ловушку) соединения висят в conntrack и не протухают, так как тарпит не дает. Например, если тарпить на слабых роутерах, то из-за того, что контрэк распух — у вас снизится (и реально снижается!) скорость коммутации пакетов (табличку долго просматривать приходится). Очень этим грешили роутеры типа DIR-100, когда запуск torrent и последующее выключение забивали контрэк так, что до провайдера пинг подскакивал до сотен. Просто потому что соединения плодились, а не полоса была занята. Сейчас с этим получше, но в любом случае проблема остается.
      Опять же, можно написать (уже написано примерно во времена появления TARPIT в iptables, но гуглить лень) генератор пакетов, который навешает у вас TARPIT соединений, которые вы сами же будете поддерживать и забивать свой контрэк, а со стороны хакера это не будут соединения, а просто пара пакетов с железяки, которая даже не знает что такое TCP.
      Решение есть: на все порты, которые -j TARPIT делать еще -t raw -j NOTRACK (ну или совсем отказаться от conntrack)

      Но такие сложности уже напоминают ситуацию — обе стороны наелись гов.. мыла, и остались при своем

      Но все же в целом с вами соглашусь: использовать -j TARPIT, если уж хочется именно потроллить ботнеты (ведь сканят именно ботнеты, вручную мало что сканят), куда практичнее, чем запускать демона на питоне или даже С, симулирующего ssh


      1. selivanov_pavel
        26.03.2019 22:57

        iptables -t raw -A PREROUTING -p tcp --dport 22 -j NOTRACK
        iptables -A INPUT -p tcp --dport 22 -j TARPIT


        UPD: увидел, что вы уже написали про NOTRACK. Но всё равно пусть коммент висит, лишним не будет. Тратить conntrack на мусорные соединения действительно как-то не очень.


  1. veselovi4
    26.03.2019 15:06
    +1

    DenyHosts еще лучше.


    1. podivilov
      26.03.2019 16:17

      Ага. А fail2ban — ещё лучше.


  1. Revertis
    26.03.2019 17:11

    Запустил питоновскую версию, добавив чуть логов. Несколько часов не было ни одного подключения, потом подзабыл об этом. Сейчас смотрю — 39 клиентов уже подключалось.


    1. Revertis
      26.03.2019 21:36
      +1

      Добавил еще немного логов, чтобы удобнее отслеживать длительность коннектов.
      В результате, 6 из 7 подключений отваливаются через 30 секунд, седьмое протянулось на 17 минут и 30 секунд.


      1. w0den
        26.03.2019 23:56
        +1

        Если хотите больше подопытных, перенесите хонейпот на порт 445 или 23. А если 80 свободен, то перенесите его туда, поскольку там вся тусовка.


  1. blind_oracle
    26.03.2019 17:37

    Не очень понятно зачем это нужно. Повесить на 22 порт, а реальный sshd поднять на рандомном? И наказывать кулхацкеров?


  1. whyme
    26.03.2019 19:17
    +2

    1378 бесполезных соединений на сервере висящих в течение 20 часов против ботнета который сканирует порты на уязвимости, за счет ресурсов зараженных пользователей, не совсем похоже на правильный подход. Всегда считал что лучше минимизировать свои затраты, чем сделать кому то хуже чем себе. Ханипоты нужны для обнаружения и предотвращения атак, но никак не для наказывания, замучаятесь наказывать.


  1. firedragon
    26.03.2019 19:58
    -1

    Я кстати в недоумении. 3 дня пытаюсь достучаться до поддержки avito и dns-shop по поводу их систем защиты. И в одном и в другом месте необычайная тупость технической поддержки.
    Дословный ответ: Наша система работает отлично, а вам не надо подключатся через VPN к нашему сайту.

    Ответ от других еще более глобален:
    image


    1. SergeyMax
      27.03.2019 09:59

      Давно известно, что авито блокирует доступ к некоторым ресурсам сайта с адресов прокси и прочих левых диапазонов. И ещё википедия не даёт статьи редактировать.


      1. Gamliel_Fishkin
        27.03.2019 12:41

        В Википедии это вынужденная мера, чтобы затруднить многократную реинкарнацию заблокированного вандала. Добросовестному участнику с положительным вкладом при необходимости выдают технический флаг исключения из IP-блокировок, позволяющий редактировать с заблокированного IP-адреса, а также через прокси, VPN и Tor; 24–25 августа 2015 года в связи с тогдашними событиями активным участникам (более трёхсот) выдали такой технический флаг, а 27 августа его почти у всех забрали за ненадобностью.


        1. SergeyMax
          27.03.2019 21:15
          +1

          Ну дак и в авито это точно такая же вынужденная мера. Только флаг не выдают.


          1. Gamliel_Fishkin
            28.03.2019 01:57

            В Википедии ограничения касаются только редактирования. Чтение Википедии через прокси, VPN и Tor не запрещено правилами Википедии; более того, там есть инструкция «Что делать, если Википедия заблокирована».


  1. Sly_tom_cat
    26.03.2019 21:49
    +1

    Python без отступов в форматировании работать не будет. Поправьте форматирование.


  1. w0den
    26.03.2019 23:45

    Мне кажется, на продакшене правильный «хонейпот» должен привести к INPUT DROP.


    1. ABATAPA
      27.03.2019 08:39

      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'.


      1. SergeyMax
        27.03.2019 10:00

        Дроп ни о чём не говорит, а вот пришедший в ответ резет явно говорит о фильтрации.


        1. ABATAPA
          27.03.2019 15:28

          Вы заблуждаетесь и плохо себе представляете функционирование сетей. Всё именно так, как я сказал.
          Когда кто-то обращается к хосту на порт, который не «слушает» ни одно приложение (порт 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… »

          Так что, прежде чем что-то безапелляционно утверждать, — проверяйте себя.


      1. w0den
        27.03.2019 21:38

        Если используется INPUT DROP, то атакующий видит FILTERED для всех портов, вне зависимости от того, открыт порт или нет. Используя REJECT, атакующий видит то же самое, только вместо FILTERED, отображается CLOSED. Однако есть проблема: REJECT, в отличии от DROP, не обрывает соединение, а всё же отвечает на запрос.

        Учитывая то, что ни в одном из этих случаев атакующий не может знать, используется тот или иной порт на целевой машине, то правильнее всего использовать DROP, а не заставить машину отвечать на ненужные запросы.


  1. LevOrdabesov
    27.03.2019 15:14

    А для ftp ничего такого нет?
    Беглый поиск не дал результата.


    1. Cenzo
      28.03.2019 04:14

      Для FTP в наше время есть переключение протокола на SFTP с авторизацией по ключу и скорейшему забыванию про существование FTP.


    1. w0den
      28.03.2019 04:56

      В своём блоге автор приводит пример для веб-сервера и говорит, что решение «идеально подходит» для создания подобных ловушек. Если немного его поправить, думаю, для FTP тоже должно работать.