---
tags: [freebsd, security]
verified: 2026-09-02
---

# FreeBSD VPS: Honeypot и мониторинг безопасности

## Обзор архитектуры

```text
Интернет
    │
    ▼
┌─────────────────────────────────────┐
│  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. При переустановке с нуля
разумнее брать этот путь, а приведённые вызовы читать как описание уже
работающей установки.

```sh
# Запуск
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

```sh
# Список 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-сессию мониторинга:

```sh
#!/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):

```sh
#!/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-сессиями

```sh
# Запустить/переключиться на мониторинг
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
```

---

## Анализ атак

### Фильтрация событий

```sh
# Успешные входы (боты, которые «взломали» 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). Чтобы увидеть всё, что делал конкретный бот:

```sh
doas bastille cmd cowrie grep "SESSION_ID" \
  /home/cowrie/cowrie/var/log/cowrie/cowrie.json
```

Типичная последовательность событий в сессии:

1. `cowrie.session.connect` — подключение (IP, порт)
2. `cowrie.client.version` — версия SSH-клиента (определяет инструмент)
3. `cowrie.client.kex` — hassh-отпечаток (уникальная подпись клиента)
4. `cowrie.login.success/failed` — попытка входа (логин, пароль)
5. `cowrie.command.input` — команды в фейковом шелле
6. `cowrie.session.file_download` — загрузка малвари
7. `cowrie.session.closed` — отключение (длительность сессии)

### Статистика

```sh
# Топ перебираемых логинов
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`

```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

```sh
# Перезагрузить правила
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`):

```text
0 4 * * * /sbin/pfctl -t bruteforce -T expire 86400
```

Удаляет записи старше 24 часов.

---

## Конфигурация Cowrie

### Принимаемые учётные данные: `etc/userdb.txt`

Путь внутри jail: `/home/cowrie/cowrie/etc/userdb.txt`

```text
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

```text
/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

```sh
# Структура датасетов
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 не запускается

```sh
# Проверить лог ошибок
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

```sh
# Проверить 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 нужно запускать вручную после перезагрузки. Для автоматизации создай скрипт в хостовой системе:

```sh
# /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"
```

```sh
doas chmod +x /usr/local/etc/rc.d/cowrie_start
doas sysrc cowrie_start_enable="YES"
```

---

## Связанные заметки

- [FreeBSD — Jails](./freebsd-jails.md) — как устроена изоляция, в которой работает Cowrie
- [FreeBSD — сеть](./freebsd-networking.md) — PF: NAT, редиректы и таблицы для honeypot-трафика
- [FreeBSD — безопасность](./freebsd-security-hardening.md) — базовый hardening хоста, на котором стоит honeypot
- [FreeBSD — мониторинг и отладка](./freebsd-monitoring-debugging.md) — анализ логов и системных событий
