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)
FuzzyWorm
26.03.2019 10:02+1Отличная статья, с удовольствием прочитал ее дважды :)
А если серьезно, то реально попробую эту технику использовать
Cobolorum
26.03.2019 10:07Вещь нужная, но не не питоне. То что автор ее на C написал позволит ее запустить даже на OpenWRT. Но еще лучше ее как модуль/правил в для примера в iptables. Как здесь ruunix.ru/597-tarpit-lovushka-v-iptables.html
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
Понадобятся хедеры ядра и компилятор, если ещё не стоят.
Mnemonik
26.03.2019 10:22+1К сожалению вещь просто веселая (и классная), но никак не полезная. И никто не будет дорабатывать скрипты. Эти сканеры работают во-первых массово, во-вторых их цели ну настолько кривые устройства, где ssh сервера реализованы такими Ляо на коленке, весь этот сонм криво настроенного IoT, что среди них девайсов со странным поведением — 50%. Вообще никто не заметит что одно соединение кривое, их у сканера будут тысячи и сами по себе без специализированного тарпита через жопу.
Fragster
26.03.2019 11:21Port knocking, имхо, удобнее и безопаснее. К тому же дорабатывать нужно только скрипты клиентов.
Anastasia_K
26.03.2019 11:36ну о чём вы, какой port knocking? Конечно же лучше потратить десяток килобайт памяти спамера ценой отдельного сервиса у себя)
pfg21
27.03.2019 09:33т.е. тарпит не сервис, а что-то такое ангельское эфемерное, не заметное для системы… :) под ддосом весьма нехило может ресурсов пожрать.
порт-кнокинг имхо гораздо надежнее. без ключа не открыт ни один лишний порт, и одного лишнего движения.
есть еще пинг-кнокинг под некоторые системы прощее стучатся получается.
begemoth3663
26.03.2019 11:46+1Вот не понимаю, зачем.
Вам шашечки или ехать?
У вас цель: обезопасить сервер или сделать мир лучше?
У меня, как правило, первая.
Поэтому sshd + blacklistd + ipfw ОТЛИЧНО справляются с данной задачей (по опыту, куда лучше fail2ban и sshguard).
И порт не меняю: а смысл?
Из-за того, что кто-то куда-то может пару раз постучать, корячиться и всегда помнить, что при ssh — одним способом порт указывать, при scp — другим?.. А скрипты: когда в одном проекте один порт, а в другом — он занят приложением?..
Безопасности добавли на ноль целых и ничего десятых, зато неудобства — на все 100 :)AnyKey80lvl
26.03.2019 12:02Для желающих тут же погрузиться в поиск: blacklistd хорош, но FreeBSD-only. Ждём, как говорится, e-buildов
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>]
begemoth3663
27.03.2019 10:25Демон sshd (при включенном UseBlacklist) отправит инфу (authentication success/failure) на blacklistd сокет, и… запишет это в лог.
настраиваемо.
Ну а blacklistd прочитает её из сокета и распарсит.
Чем оно в принципе отличается от "распарсивания" fail2ban тех же строчек прочитанных из лога, никто так и не смог мне внятно объяснить.лучше уж хотя бы тем, что не нужно в системе держать питон ради единственного fail2ban.
размер используемой памяти — очевидно же, не в пользу fail2ban.
и решение в случае sshd+blacklistd+ipfw получается "искаропки".sebres
27.03.2019 14:11"искаропки" оно было бы, если бы sshd умел всё то сам (это однако противоречило бы философии *nix).
Berkof
27.03.2019 06:26Сделать мир лучше — тоже неплохая цель, особенно если требует всего несколько килобайт на сервере.
begemoth3663
27.03.2019 11:12Это Вы так про питон пошутили? :)
eirnym
27.03.2019 23:15питон во многих сборках Linux есть по-умолчанию. Не во всех, естественно, но устанавливать специально его чаще всего не требуется.
Inanity
26.03.2019 13:09Подскажите, а какой смысл при работе Endlessh отправлять именно рандомные данные в строке с «SSH-»? Может быть можно ещё немного упростить программу?
alexanster
26.03.2019 13:41Чтоб враги сразу не догадались и заморочились поиском способа «расшифровки»?
Inanity
26.03.2019 13:59Так это до криптографии. Автор же писал, что можно отправлять любые данные до строки с версией. А просто так вещать не пойми кому свой рандом тоже не безопасно. Если генератор некачественный, то со стороны противника можно осуществлять анализ и это теоретически поспособствует другому вектору атак.
alexanster
26.03.2019 14:15Я ж не просто так взял в кавычки, я имел в виду: пускай потенциальный взломщик сидит и ломает голову, что же это такое, тратит ресурсы и время. А реальную криптографию даже в виду не имел.
Cenzo
27.03.2019 04:48Лучше как раз взять самый некачественный программный псевдогенератор (PRNG(x)), и пусть хоть сколько ломают себе голову. Потому как в системе и openssl используются совсем другие.
barbos6
26.03.2019 14:51+159348 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
Это не сделает мир лучше прямо сразу, но при относительно массовом применении намного увеличит порог вхождения как для реальных жуликов, так и для бестолковых пионэров с кривыми ручками. И реально сократит мусорный трафик.
trublast
26.03.2019 19:30+1С одной стороны да, а с другой — тарпнутые (пойманные в ловушку) соединения висят в conntrack и не протухают, так как тарпит не дает. Например, если тарпить на слабых роутерах, то из-за того, что контрэк распух — у вас снизится (и реально снижается!) скорость коммутации пакетов (табличку долго просматривать приходится). Очень этим грешили роутеры типа DIR-100, когда запуск torrent и последующее выключение забивали контрэк так, что до провайдера пинг подскакивал до сотен. Просто потому что соединения плодились, а не полоса была занята. Сейчас с этим получше, но в любом случае проблема остается.
Опять же, можно написать (уже написано примерно во времена появления TARPIT в iptables, но гуглить лень) генератор пакетов, который навешает у вас TARPIT соединений, которые вы сами же будете поддерживать и забивать свой контрэк, а со стороны хакера это не будут соединения, а просто пара пакетов с железяки, которая даже не знает что такое TCP.
Решение есть: на все порты, которые -j TARPIT делать еще -t raw -j NOTRACK (ну или совсем отказаться от conntrack)
Но такие сложности уже напоминают ситуацию — обе стороны наелисьгов..мыла, и остались при своем
Но все же в целом с вами соглашусь: использовать -j TARPIT, если уж хочется именно потроллить ботнеты (ведь сканят именно ботнеты, вручную мало что сканят), куда практичнее, чем запускать демона на питоне или даже С, симулирующего sshselivanov_pavel
26.03.2019 22:57iptables -t raw -A PREROUTING -p tcp --dport 22 -j NOTRACK
iptables -A INPUT -p tcp --dport 22 -j TARPIT
UPD: увидел, что вы уже написали про NOTRACK. Но всё равно пусть коммент висит, лишним не будет. Тратить conntrack на мусорные соединения действительно как-то не очень.
Revertis
26.03.2019 17:11Запустил питоновскую версию, добавив чуть логов. Несколько часов не было ни одного подключения, потом подзабыл об этом. Сейчас смотрю — 39 клиентов уже подключалось.
Revertis
26.03.2019 21:36+1Добавил еще немного логов, чтобы удобнее отслеживать длительность коннектов.
В результате, 6 из 7 подключений отваливаются через 30 секунд, седьмое протянулось на 17 минут и 30 секунд.w0den
26.03.2019 23:56+1Если хотите больше подопытных, перенесите хонейпот на порт 445 или 23. А если 80 свободен, то перенесите его туда, поскольку там вся тусовка.
blind_oracle
26.03.2019 17:37Не очень понятно зачем это нужно. Повесить на 22 порт, а реальный sshd поднять на рандомном? И наказывать кулхацкеров?
whyme
26.03.2019 19:17+21378 бесполезных соединений на сервере висящих в течение 20 часов против ботнета который сканирует порты на уязвимости, за счет ресурсов зараженных пользователей, не совсем похоже на правильный подход. Всегда считал что лучше минимизировать свои затраты, чем сделать кому то хуже чем себе. Ханипоты нужны для обнаружения и предотвращения атак, но никак не для наказывания, замучаятесь наказывать.
firedragon
26.03.2019 19:58-1Я кстати в недоумении. 3 дня пытаюсь достучаться до поддержки avito и dns-shop по поводу их систем защиты. И в одном и в другом месте необычайная тупость технической поддержки.
Дословный ответ: Наша система работает отлично, а вам не надо подключатся через VPN к нашему сайту.
Ответ от других еще более глобален:
SergeyMax
27.03.2019 09:59Давно известно, что авито блокирует доступ к некоторым ресурсам сайта с адресов прокси и прочих левых диапазонов. И ещё википедия не даёт статьи редактировать.
Gamliel_Fishkin
27.03.2019 12:41В Википедии это вынужденная мера, чтобы затруднить многократную реинкарнацию заблокированного вандала. Добросовестному участнику с положительным вкладом при необходимости выдают технический флаг исключения из IP-блокировок, позволяющий редактировать с заблокированного IP-адреса, а также через прокси, VPN и Tor; 24–25 августа 2015 года в связи с тогдашними событиями активным участникам (более трёхсот) выдали такой технический флаг, а 27 августа его почти у всех забрали за ненадобностью.
SergeyMax
27.03.2019 21:15+1Ну дак и в авито это точно такая же вынужденная мера. Только флаг не выдают.
Gamliel_Fishkin
28.03.2019 01:57В Википедии ограничения касаются только редактирования. Чтение Википедии через прокси, VPN и Tor не запрещено правилами Википедии; более того, там есть инструкция «Что делать, если Википедия заблокирована».
Sly_tom_cat
26.03.2019 21:49+1Python без отступов в форматировании работать не будет. Поправьте форматирование.
w0den
26.03.2019 23:45Мне кажется, на продакшене правильный «хонейпот» должен привести к
INPUT DROP
.ABATAPA
27.03.2019 08:39DROP сразу же говорит о том, что порт открыт и трафик фильтруется.
Правильнее
-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'.SergeyMax
27.03.2019 10:00Дроп ни о чём не говорит, а вот пришедший в ответ резет явно говорит о фильтрации.
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… »
Так что, прежде чем что-то безапелляционно утверждать, — проверяйте себя.
w0den
27.03.2019 21:38Если используется
INPUT DROP
, то атакующий видитFILTERED
для всех портов, вне зависимости от того, открыт порт или нет. ИспользуяREJECT
, атакующий видит то же самое, только вместоFILTERED
, отображаетсяCLOSED
. Однако есть проблема:REJECT
, в отличии отDROP
, не обрывает соединение, а всё же отвечает на запрос.
Учитывая то, что ни в одном из этих случаев атакующий не может знать, используется тот или иной порт на целевой машине, то правильнее всего использоватьDROP
, а не заставить машину отвечать на ненужные запросы.
LevOrdabesov
27.03.2019 15:14А для ftp ничего такого нет?
Беглый поиск не дал результата.Cenzo
28.03.2019 04:14Для FTP в наше время есть переключение протокола на SFTP с авторизацией по ключу и скорейшему забыванию про существование FTP.
w0den
28.03.2019 04:56В своём блоге автор приводит пример для веб-сервера и говорит, что решение «идеально подходит» для создания подобных ловушек. Если немного его поправить, думаю, для FTP тоже должно работать.
AlexSpirit
А текст вообще вычитывался перед публикацией? Или подразумевается, что до некоторых с первого раза не доходит? :-)
lagudal
я не
глухойслепой, я не слепой. Поэтому не нужно мне повторять все по два раза, по два раза ))))