Обзор архитектуры
Интернет
│
▼
┌─────────────────────────────────────┐
│ FreeBSD Host (pf firewall) │
│ │
│ vtnet0 (внешний IP) │
│ ├── порт 22 → rdr → jail cowrie │
│ ├── порт 52222 → настоящий SSH │
│ │ │
│ bastille0 (loopback bridge) │
│ └── 10.17.89.0/24 │
│ └── 10.17.89.1 — jail cowrie │
│ └── Cowrie :2222 │
└─────────────────────────────────────┘
Реальный SSH живёт на нестандартном порту (52222), защищён ключами и rate limiting. Порт 22 проброшен через pf в jail с Cowrie — SSH-honeypot, который имитирует уязвимый сервер и записывает все действия атакующих.
Повседневные операции
Управление Cowrie
Команды ниже относятся к установке из клона репозитория, где точка входа —
src/cowrie/scripts/cowrie.py. Апстрим с тех пор переехал: Cowrie 3.x ставится
из PyPI в виртуальное окружение и управляется собственной командой (cowrie init,
cowrie start), минимальная версия Python — 3.10. При переустановке с нуля
разумнее брать этот путь, а приведённые вызовы читать как описание уже
работающей установки.
# Запуск
doas bastille cmd cowrie su -m cowrie -c \
"/usr/local/bin/python3.11 /home/cowrie/cowrie/src/cowrie/scripts/cowrie.py start"
# Остановка
doas bastille cmd cowrie su -m cowrie -c \
"/usr/local/bin/python3.11 /home/cowrie/cowrie/src/cowrie/scripts/cowrie.py stop"
# Перезапуск
doas bastille cmd cowrie su -m cowrie -c \
"/usr/local/bin/python3.11 /home/cowrie/cowrie/src/cowrie/scripts/cowrie.py stop"
doas bastille cmd cowrie su -m cowrie -c \
"/usr/local/bin/python3.11 /home/cowrie/cowrie/src/cowrie/scripts/cowrie.py start"
# Статус (проверить, слушает ли порт)
doas bastille cmd cowrie sockstat -l | grep 2222
Управление jail
# Список jail
doas bastille list
# Войти в консоль jail
doas bastille console cowrie
# Запуск/остановка jail
doas bastille start cowrie
doas bastille stop cowrie
# ZFS-снапшот jail (перед изменениями)
doas zfs snapshot zroot/bastille/jails/cowrie@backup-$(date +%Y%m%d)
# Список снапшотов
zfs list -t snapshot
# Откат к снапшоту
doas zfs rollback zroot/bastille/jails/cowrie@backup-YYYYMMDD
Мониторинг
Скрипты мониторинга
Система мониторинга состоит из двух скриптов:
/usr/local/bin/honeypot-monitor — запускает/переключает tmux-сессию мониторинга:
#!/bin/sh
SESSION="honeypot"
# Если сессия уже есть — переключиться/подключиться
if tmux has-session -t $SESSION 2>/dev/null; then
if [ -n "$TMUX" ]; then
exec tmux switch-client -t $SESSION
else
exec tmux attach -t $SESSION
fi
fi
# Создать сессию с логом в реальном времени (без debug и сырых дампов)
tmux new-session -d -s $SESSION -n logs \
"doas bastille cmd cowrie tail -f /home/cowrie/cowrie/var/log/cowrie/cowrie.log | grep --line-buffered -v -E 'debug|discarded direct-tcp'"
# Панель снизу — успешные входы и команды
tmux split-window -t $SESSION:logs -v \
"doas bastille cmd cowrie tail -f /home/cowrie/cowrie/var/log/cowrie/cowrie.json | grep --line-buffered -E 'login.success|command'"
# Второе окно — статистика
tmux new-window -t $SESSION -n stats "honeypot-stats"
# Вернуться на первое окно и переключиться/подключиться
tmux select-window -t $SESSION:logs
if [ -n "$TMUX" ]; then
tmux switch-client -t $SESSION
else
tmux attach -t $SESSION
fi
/usr/local/bin/honeypot-stats — обновляемая статистика (вынесен отдельно, чтобы избежать проблем с экранированием кавычек в tmux):
#!/bin/sh
while true; do
clear
echo "=== Attacks today (connections) ==="
doas bastille cmd cowrie grep -c "session.connect" /home/cowrie/cowrie/var/log/cowrie/cowrie.json 2>/dev/null
echo "=== Successful logins today ==="
doas bastille cmd cowrie grep -c "login.success" /home/cowrie/cowrie/var/log/cowrie/cowrie.json 2>/dev/null
echo "=== Bruteforce bans ==="
doas pfctl -t bruteforce -T show 2>/dev/null | wc -l
echo "=== Active connections on port 22 ==="
doas pfctl -s states 2>/dev/null | grep ":22 " | wc -l
sleep 10
done
Оба скрипта должны быть исполняемыми: doas chmod +x /usr/local/bin/honeypot-monitor /usr/local/bin/honeypot-stats
Примечания по статистике:
- Attacks today считает только
session.connect(уникальные подключения), а не все строки лога — иначе число завышается в 5–10 раз, т.к. каждая сессия генерирует несколько событий. - Active connections почти всегда 0 — боты подключаются на доли секунды, и в момент опроса (раз в 10 сек) активных соединений обычно нет.
- Bruteforce bans — защита порта 52222 (настоящий SSH), а не порта 22 (honeypot). На honeypot rate limiting не применяется намеренно.
Примечание по FreeBSD: стандартная утилита watch во FreeBSD — сетевой сниффер, не аналог GNU watch. Для периодического выполнения команд используется цикл while true или пакет cmdwatch (pkg install cmdwatch).
Управление tmux-сессиями
# Запустить/переключиться на мониторинг
honeypot-monitor
# Вернуться в рабочую сессию
Ctrl+b s # список сессий, выбрать стрелками
Ctrl+b ) # следующая сессия
# Навигация внутри honeypot-сессии
Ctrl+b n # следующее окно (logs → stats)
Ctrl+b p # предыдущее окно
Ctrl+b ↑↓ # переключение между панелями в окне logs
# Отключиться от tmux (сессия продолжает работать)
Ctrl+b d
# Убить сессию мониторинга и пересоздать
tmux kill-session -t honeypot
honeypot-monitor
Анализ атак
Фильтрация событий
# Успешные входы (боты, которые «взломали» honeypot)
doas bastille cmd cowrie grep "login.success" \
/home/cowrie/cowrie/var/log/cowrie/cowrie.json
# Неудачные попытки входа
doas bastille cmd cowrie grep "login.failed" \
/home/cowrie/cowrie/var/log/cowrie/cowrie.json
# Команды, выполненные ботами после входа
doas bastille cmd cowrie grep "command" \
/home/cowrie/cowrie/var/log/cowrie/cowrie.json
# Файлы, которые боты пытались скачать
doas bastille cmd cowrie grep "session.file_download" \
/home/cowrie/cowrie/var/log/cowrie/cowrie.json
# Попытки использовать сервер как прокси (port forwarding)
doas bastille cmd cowrie grep "direct-tcp" \
/home/cowrie/cowrie/var/log/cowrie/cowrie.json
Анализ конкретной сессии
Каждая сессия имеет уникальный ID (поле session в JSON). Чтобы увидеть всё, что делал конкретный бот:
doas bastille cmd cowrie grep "SESSION_ID" \
/home/cowrie/cowrie/var/log/cowrie/cowrie.json
Типичная последовательность событий в сессии:
cowrie.session.connect— подключение (IP, порт)cowrie.client.version— версия SSH-клиента (определяет инструмент)cowrie.client.kex— hassh-отпечаток (уникальная подпись клиента)cowrie.login.success/failed— попытка входа (логин, пароль)cowrie.command.input— команды в фейковом шеллеcowrie.session.file_download— загрузка малвариcowrie.session.closed— отключение (длительность сессии)
Статистика
# Топ перебираемых логинов
doas bastille cmd cowrie grep "login" \
/home/cowrie/cowrie/var/log/cowrie/cowrie.json \
| grep -o '"username":"[^"]*"' | sort | uniq -c | sort -rn | head -20
# Топ перебираемых паролей
doas bastille cmd cowrie grep "login" \
/home/cowrie/cowrie/var/log/cowrie/cowrie.json \
| grep -o '"password":"[^"]*"' | sort | uniq -c | sort -rn | head -20
# Топ IP-адресов атакующих
doas bastille cmd cowrie grep "session.connect" \
/home/cowrie/cowrie/var/log/cowrie/cowrie.json \
| grep -o '"src_ip":"[^"]*"' | sort | uniq -c | sort -rn | head -20
# Топ SSH-клиентов (определяет инструменты сканирования)
doas bastille cmd cowrie grep "client.version" \
/home/cowrie/cowrie/var/log/cowrie/cowrie.json \
| grep -o '"version":"[^"]*"' | sort | uniq -c | sort -rn | head -20
# Топ hassh-отпечатков (группировка по инструменту)
doas bastille cmd cowrie grep "client.kex" \
/home/cowrie/cowrie/var/log/cowrie/cowrie.json \
| grep -o '"hassh":"[^"]*"' | sort | uniq -c | sort -rn | head -20
# Количество подключений за сегодня
doas bastille cmd cowrie grep "$(date -u +%Y-%m-%d)" \
/home/cowrie/cowrie/var/log/cowrie/cowrie.json \
| grep -c "session.connect"
Наблюдённые типы атак
1. Распределённый брутфорс (ботнет 154.49.0.0/16)
Признаки: hassh 0a07365cc01fa9fc82608ba4019af499, SSH-клиент SSH-2.0-Go, логин administrator, ротация IP (один IP — одна попытка). Словарь включает русский транслит: ghbdtn (привет), fktrcfylh (александр), а также числовые пароли: 444444, 7654321, 147852369.
После успешного входа выполняет разведывательный скрипт за 0.8 секунды: uname -a, id, cat /etc/*release, uptime, ps aux, ss -lpunt, /proc/cpuinfo, free -h, cat /etc/passwd, ip addr, df -h. Собирает полный профиль сервера (CPU, RAM, сеть, пользователи) для оценки пригодности под майнинг или DDoS.
2. Прокси-сканер (204.76.203.83)
Признаки: hassh a289c065bf37397b69226bd770e33124, логин admin/admin. Не выполняет команд, вместо этого запрашивает direct-tcpip (SSH port forwarding) к ipv4.icanhazip.com:443 — проверяет, можно ли использовать сервер как прокси для анонимизации трафика. Предварительно делает TCP-скан (подключение на 0.0 сек), через 10–15 сек — реальная попытка. Возвращается каждые ~25 минут.
JA4-отпечаток TLS: t12d131000_f57a46bbacb6_27f0a1fdd87d — идентифицирует TLS-клиент бота, аналог hassh для TLS-соединений.
3. Минималистичная разведка платформы (183.94.33.160)
Признаки: hassh 98f63c4d9c87edbd97ed4747fa031019, пароли из «креативного» словаря. Выполняет одну команду uname -s -m — определяет ОС и архитектуру. Это первый этап многоэтапной атаки: сначала определить платформу, потом вернуться с подходящим бинарником малвари.
4. Перебор украденных SSH-ключей (139.19.117.197)
Признаки: разные hassh-отпечатки с одного IP (несколько инструментов). Пытается войти по SSH-ключу (fingerprint fb:45:99:e0:...), пароли не перебирает. Более целевая атака — у бота есть база украденных ключей.
Ключевые идентификаторы для анализа
hassh — отпечаток SSH-клиента
Формируется из набора алгоритмов шифрования, которые предлагает клиент. Позволяет идентифицировать конкретный инструмент независимо от IP-адреса.
| hassh | Инструмент/ботнет |
|---|---|
0a07365cc01fa9fc82608ba4019af499 |
Ботнет 154.49.0.x (разведка) |
a289c065bf37397b69226bd770e33124 |
Прокси-сканер |
98f63c4d9c87edbd97ed4747fa031019 |
Минималистичный разведчик |
f1e5e9d24e5e345e8745613bde22d532 |
Перебор SSH-ключей |
JA4 — отпечаток TLS-клиента
Аналог hassh для TLS-соединений. Формируется из параметров TLS ClientHello (шифронаборы, расширения). Актуален для ботов, использующих port forwarding.
SSH-клиенты
| Версия | Что это |
|---|---|
SSH-2.0-Go |
Сканер на Go (masscan, zgrab и подобные) |
SSH-2.0-libssh2 |
Автоматизированный инструмент |
SSH-2.0-paramiko |
Python-скрипт (часто ботнет) |
SSH-2.0-PUTTY |
Может быть ручная атака |
Пароли-транслит
Ботнеты с русскоязычным словарём используют пароли, набранные в английской раскладке:
| Что вводят | Что имели в виду |
|---|---|
ghbdtn |
привет |
fktrcfylh |
александр |
Файрвол (pf)
Текущий конфиг: /etc/pf.conf
ext_if = "vtnet0"
jail_if = "bastille0"
ssh_port = "52222"
jail_net = "10.17.89.0/24"
table <bruteforce> persist
set skip on lo0
nat on $ext_if from $jail_net to any -> ($ext_if)
rdr on $ext_if proto tcp to port 22 -> 10.17.89.1 port 2222
block in all
pass out all keep state
block in quick on $ext_if from <bruteforce>
pass in on $ext_if proto tcp to port $ssh_port \
keep state (max-src-conn-rate 5/30, overload <bruteforce> flush global)
pass in on $ext_if proto tcp to 10.17.89.1 port 2222
pass on $jail_if
Команды pf
# Перезагрузить правила
doas pfctl -f /etc/pf.conf
# Текущие правила фильтрации
doas pfctl -s rules
# NAT и redirect правила
doas pfctl -s nat
# Активные соединения
doas pfctl -s states
# Общая статистика (заблокировано/пропущено)
doas pfctl -s info
# Таблица заблокированных IP (bruteforce на порту 52222)
doas pfctl -t bruteforce -T show
# Количество заблокированных IP
doas pfctl -t bruteforce -T show | wc -l
# Разблокировать IP
doas pfctl -t bruteforce -T delete <ip-адрес>
Автоочистка таблицы bruteforce
В crontab (doas crontab -e):
0 4 * * * /sbin/pfctl -t bruteforce -T expire 86400
Удаляет записи старше 24 часов.
Конфигурация Cowrie
Принимаемые учётные данные: etc/userdb.txt
Путь внутри jail: /home/cowrie/cowrie/etc/userdb.txt
root:x:*
admin:x:*
administrator:x:*
user:x:*
test:x:*
guest:x:*
ubuntu:x:*
oracle:x:*
postgres:x:*
Формат: username:x:password, где * — любой пароль. После изменения требуется перезапуск Cowrie.
Основной конфиг: etc/cowrie.cfg
Путь внутри jail: /home/cowrie/cowrie/etc/cowrie.cfg
Ключевые параметры:
hostname— имя хоста, которое видят боты (установлено: svr01)listen_endpoints— порт (tcp:2222:interface=0.0.0.0)[output_jsonlog]— JSON-логирование (enabled = true)
Расположение файлов внутри jail
/home/cowrie/cowrie/
├── etc/
│ ├── cowrie.cfg # основной конфиг
│ ├── cowrie.cfg.dist # дефолтный конфиг (справка)
│ └── userdb.txt # принимаемые логины/пароли
├── var/
│ ├── log/cowrie/
│ │ ├── cowrie.log # текстовый лог
│ │ └── cowrie.json # структурированный JSON-лог
│ ├── lib/cowrie/downloads/ # скачанная ботами малварь
│ ├── lib/cowrie/tty/ # записи терминальных сессий
│ └── run/cowrie.pid # PID-файл
└── src/cowrie/scripts/
└── cowrie.py # скрипт запуска/остановки
Время в логах — UTC (захардкожено в Twisted). Для Европы (CET/CEST) сдвиг +1/+2 часа.
ZFS
# Структура датасетов
zfs list -r zroot/bastille
# Снапшот перед обновлениями
doas zfs snapshot zroot/bastille/jails/cowrie@pre-update
# Список снапшотов
zfs list -t snapshot
# Откат
doas zfs rollback zroot/bastille/jails/cowrie@pre-update
# Удалить старый снапшот
doas zfs destroy zroot/bastille/jails/cowrie@old-snapshot
# Проверить использование диска
zfs list -o name,used,avail,refer
df -h
Диагностика проблем
Cowrie не запускается
# Проверить лог ошибок
doas bastille cmd cowrie cat /home/cowrie/cowrie/var/log/cowrie/cowrie.log | tail -30
# Проверить, не занят ли порт
doas bastille cmd cowrie sockstat -l | grep 2222
# Проверить, жив ли процесс
doas bastille cmd cowrie ps aux | grep cowrie
# Убить зависший процесс
doas bastille cmd cowrie kill $(cat /home/cowrie/cowrie/var/run/cowrie.pid)
Боты не попадают в honeypot
# Проверить rdr-правило
doas pfctl -s nat | grep rdr
# Проверить, открыт ли порт 22 снаружи
doas pfctl -s rules | grep 22
# Проверить, слушает ли Cowrie
doas bastille cmd cowrie sockstat -l | grep 2222
# Проверить jail
doas bastille list
Потеря SSH-доступа
Если заблокировал себя в pf — подключись через VNC/IPMI-консоль хостера и исправь /etc/pf.conf, затем pfctl -f /etc/pf.conf.
Автозапуск Cowrie при перезагрузке
На данный момент Cowrie нужно запускать вручную после перезагрузки. Для автоматизации создай скрипт в хостовой системе:
# /usr/local/etc/rc.d/cowrie_start (на хосте, не в jail)
#!/bin/sh
# REQUIRE: bastille
# PROVIDE: cowrie_start
. /etc/rc.subr
name="cowrie_start"
start_cmd="cowrie_start"
cowrie_start() {
bastille cmd cowrie su -m cowrie -c \
"/usr/local/bin/python3.11 /home/cowrie/cowrie/src/cowrie/scripts/cowrie.py start"
}
load_rc_config $name
run_rc_command "$1"
doas chmod +x /usr/local/etc/rc.d/cowrie_start
doas sysrc cowrie_start_enable="YES"
Связанные заметки
- FreeBSD — Jails — как устроена изоляция, в которой работает Cowrie
- FreeBSD — сеть — PF: NAT, редиректы и таблицы для honeypot-трафика
- FreeBSD — безопасность — базовый hardening хоста, на котором стоит honeypot
- FreeBSD — мониторинг и отладка — анализ логов и системных событий
Из библиотеки института уносят только знания. Читателей здесь не считают: посещение не регистрируется, отметок в издании не остаётся, счётчиков нет ни у одного издания фонда.
Издание пополняется и пересверяется. Текст доступен на условиях CC BY-SA 4.0 — унесённое можно передавать дальше на тех же условиях.