Post

Endlessh (SSH Tarpit): як змусити хакерських ботів чекати вічність на вашому VPS

Endlessh (SSH Tarpit): як змусити хакерських ботів чекати вічність на вашому VPS

🇬🇧 Read this article in English


Кожен, хто орендував хоча б один публічний VPS-сервер, знає сумну реальність: уже через 15 хвилин після активації IP-адреси системний журнал /var/log/auth.log починає тріщати по швах.

Сотні автоматизованих ботнетів та скрипт-кідіс з усього світу цілодобово сканують стандартний порт 22, перебираючи найпростіші паролі: admin, root, test, qwerty.

Зазвичай системні адміністратори захищаються класично:

  1. Переносять SSH на випадковий порт.
  2. Встановлюють утиліту fail2ban, яка блокує IP після кількох невдалих спроб.

Але подумайте самі: коли fail2ban відкидає атакувальника, бот миттєво звільняє свій мережевий сокет і йде сканувати наступну жертву. А що, якщо замість блокування… змусити бота чекати вічність?

Саме так працює концепція SSH Tarpit (Смоляна яма), а найкращим її втіленням є крихітна утиліта Endlessh.

Логи та моніторинг спійманих ботів у Endlessh Мал. 1. Термінал Endlessh: боти застряють у смоляній ямі на 24 години і навіть на 3 дні


Що таке Endlessh і як працює «Смоляна яма»?

Згідно з офіційним стандартом протоколу SSH (RFC 4253, розділ 4.2), перед тим, як сервер і клієнт почнуть узгоджувати версію шифрування, сервер має право відправити довільний текстовий заголовок (банер). Клієнт зобов’язаний його прочитати.

Endlessh експлуатує це правило з витонченим знущанням:

  1. Бот підключається до порту 22 у надії знайти вхід до сервера.
  2. Endlessh приймає підключення, але не просить пароль.
  3. Замість цього він починає відправляти випадкові рядки банера зі швидкістю… один рядок раз на 10 секунд.
  4. Скрипти автоматизованих сканерів зазвичай не мають коротких таймаутів на стадії вітального банера, тому вони сідають на гачок і зависають на години, дні або навіть тижні.
1
2
3
4
5
6
7
8
9
[ Хакерський Бот ]
        │
        ▼ (Спроба підключення на порт 22)
[ Endlessh Tarpit ]
        │ ── (Рядок 1) ──> [Чекає 10 секунд...]
        │ ── (Рядок 2) ──> [Чекає 10 секунд...]
        │ ── (Рядок 3) ──> [Чекає 10 секунд...]
        ▼
   Бот заблокований на тижні! Ресурси атакуючого вичерпано.

При цьому сам Endlessh написаний на C (або Go), використовує неблокуючий асинхронний механізм poll() і споживає менше 2-3 МБ оперативної пам’яті, навіть коли тримає тисячі атакуючих з’єднань одночасно!


Крок 1. Переносимо справжній SSH на безпечний порт

Перш ніж відкрити пастку на порту 22, необхідно перенести справжній вхід до сервера на інший порт (наприклад, 1234 або будь-який інший високий порт).

⚠️ Увага: Не закривайте поточну сесію термінала, поки не перевірите новий порт у паралельному вікні, щоб не втратити доступ до сервера!

  1. Відкрийте конфігурацію SSH-демона:
    1
    
    sudo nano /etc/ssh/sshd_config
    
  2. Знайдіть рядок #Port 22 або Port 22, розкоментуйте його та вкажіть ваш новий порт:
    1
    
    Port 1234
    
  3. Дозвольте новий порт у фаєрволі вашої системи:
    • Якщо у вас UFW (Ubuntu/Debian):
      1
      2
      
      sudo ufw allow 1234/tcp
      sudo ufw reload
      
    • Якщо у вас Firewalld (CentOS/AlmaLinux/RHEL):
      1
      2
      
      sudo firewall-cmd --permanent --add-port=1234/tcp
      sudo firewall-cmd --reload
      
  4. Якщо ви використовуєте Fail2ban, обов’язково оновіть порт у конфігурації джейлу /etc/fail2ban/jail.local (параметр port = 1234 у секції [sshd]) і перезапустіть службу:
    1
    
    sudo systemctl restart fail2ban
    
  5. Перезапустіть службу OpenSSH:
    1
    
    sudo systemctl restart sshd   # або 'sudo systemctl restart ssh' на Debian/Ubuntu
    
  6. Обов’язкова перевірка: Відкрийте нове вікно термінала на своєму комп’ютері та увійдіть:
    1
    
    ssh -p 1234 user@your-server-ip
    

    Якщо вхід успішний — чудово! Тепер стандартний порт 22 вільний для нашої пастки.


Крок 2. Розгортання Endlessh у Docker

Найчистіший та найефективніший спосіб розгорнути пастку — використати готовий Docker-образ shizunge/endlessh-go з Docker Hub. На відміну від застарілих збірок, ця версія написана на Go, нативно підтримує експорт метрик для Prometheus та вміє автоматично визначати геолокацію атакуючих.

💡 Зверніть увагу: Образ endlessh-go налаштовується саме через аргументи командного рядка (CLI flags), а не через змінні середовища ENV.

Варіант А: Через docker-compose.yml

  1. Створимо каталог для сервісу:
    1
    
    sudo mkdir -p /opt/endlessh && cd /opt/endlessh
    
  2. Створимо файл docker-compose.yml:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    version: '3.8'
    
    services:
      endlessh:
        image: shizunge/endlessh-go:latest
        container_name: endlessh
        restart: unless-stopped
        ports:
          - "22:2222"   # Зовнішній порт 22 перенаправляємо на порт пастки 2222
          - "2112:2112" # Метрики для Prometheus
        command:
          - -prometheus_enabled       # Обов'язково вмикаємо сервер метрик (за замовчуванням вимкнено!)
          - -geoip_supplier=ip-api    # Автоматичне визначення країни та Geohash ботів через ip-api.com
          - -interval_ms=5000         # Затримка між рядками (5 сек = 5000 мс)
          - -logtostderr
          - -v=1
    
  3. Запускаємо контейнер:
    1
    
    docker compose up -d
    

Варіант Б: Пряма команда docker run

Якщо ви віддаєте перевагу швидкому запуску через одну команду:

1
2
3
4
5
6
7
8
9
10
11
docker run -d \
  --name endlessh \
  --restart unless-stopped \
  -p 22:2222 \
  -p 2112:2112 \
  shizunge/endlessh-go:latest \
  -prometheus_enabled \
  -geoip_supplier=ip-api \
  -interval_ms=5000 \
  -logtostderr \
  -v=1

Чому саме такі налаштування?

  • -interval_ms=5000 (5 секунд): Багато бот-сканерів мають короткий idle timeout (очікування відповіді на сокеті 5–10 секунд). Якщо відправляти банери кожні 5 секунд, боти не відпадають через тишу на лінії.
  • -geoip_supplier=ip-api: Дозволяє сервісу самостійно звертатися до безкоштовного API й отримувати Geohash та країну для кожної IP-адреси без потреби завантажувати й оновлювати локальні бази MaxMind.
  • Переконайтеся, що порт 22 дозволений у фаєрволі вашого сервера.

Крок 3. Насолоджуємося видовищем (Аналіз логів)

Уже за кілька хвилин перші боти відчують гостинність нашої смоляної ями. Перегляньте живий журнал Endlessh:

1
docker logs -f endlessh

Реальний консольний лог підключень у Endlessh Мал. 1. Реальний лог роботи Endlessh на нашому VPS: боти масово потрапляють у пастку

У логах чітко видно життєвий цикл кожного спійманого бота:

  • ACCEPT host=... — бот підключився до 22-го порту і почав повільно читати нескінченний банер.
  • CLOSE host=... time=... bytes=... — з’єднання розірвано із зазначенням часу утримання та кількості переданих байтів.

Чому деякі боти відпадають через 10–20 секунд?

У логах ви помітите, що чимало ботів відвалюються з позначкою time=10.00... або time=20.00.... Це відбувається тому, що в багатьох масових автоматизованих сканерах (наприклад, написаних на Python Paramiko або скриптах на Go) жорстко зашито клієнтський таймаут у 10–20 секунд на встановлення з’єднання. Якщо за цей час повноцінний SSH handshake не завершився — бот сам надсилає FIN/RST пакет.

Проте навіть 20 секунд затримки — це великий успіх: для швидкісного сканера заблокований робочий потік збиває темп сканування тисяч хостів. А менш агресивні або повторні спроби брутфорсу зависають на десятки хвилин, години або навіть дні!


Бонус: Гарний моніторинг через Grafana та Prometheus

Оскільки ми увімкнули прапорець -prometheus_enabled, endlessh-go експортує детальну статистику на порту 2112/metrics.

Живий дашборд Endlessh у Grafana Мал. 2. Живий дашборд у Grafana: понад 200 спійманих ботів, 12 годин сумарного часу утримання, мапа та статистика країн

1. Додавання таргета в Prometheus

У файлі конфігурації prometheus.yml вашого сервера моніторингу додайте новий scrape job:

1
2
3
4
5
scrape_configs:
  - job_name: 'vps-endlessh'
    scrape_interval: 10s
    static_configs:
      - targets: ['your-vps-ip:2112'] # Публічна IP, домен або Tailscale IP вашого VPS

Перезавантажте Prometheus (docker restart prometheus або через HTTP POST на /-/reload).

2. Імпорт готового дашборду в Grafana

Офіційний дашборд на Grafana Labs має ID 15156 (Endlessh):

  1. У Grafana відкрийте: Dashboards ➡️ New ➡️ Import.
  2. Введіть ID 15156 і натисніть Load.
  3. Оберіть джерело даних Prometheus і натисніть Import.

3. Два важливих налаштування дашборду (Лайфхаки)

Після імпорту зробіть дашборд доступним для редагування, натиснувши кнопку Make editable у правому верхньому кутку.

1. Прибираємо водяний знак “API KEY REQUIRED” на карті

За замовчуванням панель карти намагається завантажити підкладку Carto, яка вимагає платної або зареєстрованої авторизації.

  • Натисніть три крапки на панелі Locations ➡️ Edit.
  • У правому меню розгорніть блок Map layers ➡️ Basemap (Layer 0).
  • У пункті Type / Theme змініть тему на Open Street Map (вона абсолютно безкоштовна і працює без жодних ключів).

2. Якщо карта порожня (фікс для сучасних версій Grafana 9 / 10 / 13)

В оригінальному дашборді дані для карти бралися через 4 застарілі трансформації groupBy, де в сучасних версіях Grafana губиться поле координат. Найпростіше й найнадійніше — перемкнути карту на прямий запит:

  • У тій самій панелі Locations перейдіть у вкладку Query (знизу зліва).
  • Замість -- Dashboard -- оберіть ваше джерело Prometheus.
  • Вставте прямий запит:
    sum by (geohash, country, location) (endlessh_client_open_count)
    
  • Увімкніть перемикач Instant та оберіть Format: Table.
  • Перейдіть на сусідню вкладку Transformations і видаліть старі трансформації (іконка кошика 🗑️).
  • Праворуч у меню Map layers ➡️ Layer 1 (Markers) переконайтеся, що у полі Location mode обрано Geohash, а у Geohash field стоїть geohash.
  • Натисніть Apply та збережіть дашборд.

Точки атакуючих одразу з’являться на карті світу разом із назвами міст та країн!


Висновок: Чому це найкращий тролінг ботів?

Endlessh — це не просто весела забавка, а філософія активного цифрового опору:

  1. Зниження навантаження: Замість постійного опрацювання тисяч спроб автентифікації процесором OpenSSH, ви зв’язуєте руки ботам в один нескінченний потік.
  2. Внесок у кібербезпеку інтернету: Кожен ботнет має обмежену кількість одночасних TCP-з’єднань. Утримуючи сотні ботів на своєму сервері, ви фізично рятуєте чийсь чужий непропатчений сервер від підбору паролів.

Спробуйте розгорнути Endlessh на своєму VPS — це той рідкісний випадок, коли спостерігати за системними логами приємніше, ніж дивитися серіал! 🪤✨

This post is licensed under CC BY 4.0 by the author.