---
date: 2026-05-20
type: decision
tags: [security, incident, benelux, openwrt, ssh, firewall]
status: closed
severity: high
---

# Бенелюкс OpenWrt — взлом через SSH brute-force на WAN

## Что произошло

В ходе плановой проверки в **15:38 MSK** на `OpenWrt Benelux` (Cudy TR3000, NetBird `100.70.207.97`, WAN `45.143.21.60`) обнаружена активная компрометация:

- **LA = 4.0** на 4-ядерном MT7981, CPU 82% idle (нагрузка не на CPU, а на сеть+OOM-loop)
- **19 параллельных SSH-сессий** от чужих IP: `185.244.183.107` (RU), `51.77.53.0/24` и `51.38.148.97` (OVH FR), `108.181.123.93`, `51.75.55.2`
- Каждая сессия рассылала **спам через SMTP 25/465/587** на сотни IP (десятки соединений на момент анализа)
- Также параллельно — попытки на **Docker API 2375** (поиск открытых демонов для распространения)
- Cron `@reboot /tmp/.2424` (тело уже самоудалилось)
- `/root/.bash_history` и `.ash_history` отсутствуют — следы зачищены

## Вектор атаки

**SSH-сервер слушал на WAN (eth0)**, пароль `root:1qaz!QAZ` — общий по всей инфраструктуре. WAN IP `45.143.21.60` публичный → brute force с открытого интернета. После взлома атакующие держали постоянные авторизованные сессии и из своих shell-ов запускали спам напрямую.

> Ранняя гипотеза о malware-процессах под именами `systemd`/`sshd` оказалась ложной — это были обычные процессы атакующих в их собственных dropbear-shell. На OpenWrt нет ни systemd, ни sshd; имена `dropbear` в `netstat` — это родительские SSH-сессии злоумышленников.

## Что сделано (без ребута)

| Шаг | Команда / артефакт |
|---|---|
| 1. Заблокировать спам | `nft insert rule inet fw4 output oifname eth0 tcp dport {25,465,587,2375} drop` (+ `forward`) |
| 2. Заблокировать вход SSH с WAN | `nft insert rule inet fw4 input iifname eth0 tcp dport 22 drop` |
| 3. Убить 19 атакующих сессий | `kill -9` всех `dropbear` PID с не-NetBird foreign IP |
| 4. Положить ключ | `/etc/dropbear/authorized_keys` = mac-ed25519 (см. `~/.ssh/id_ed25519.pub`) |
| 5. Поменять пароль root | новый — в auto-memory (НЕ в vault) |
| 6. Удалить вредоносную крон-запись | `@reboot /tmp/.2424` вычищено, осталось только `13 9 * * * /usr/bin/podkop list_update` |
| 7. Persist firewall | `/etc/nftables.d/99-incident-20260520.nft` + `fw4 reload` |

После `fw4 reload` роутер автоматически ребутнулся (вероятно watchdog отреагировал на reload в момент OOM-loop). После ребута: правила подхватились из `/etc/nftables.d/`, ключ сработал, новый пароль активен, cron чистый.

## Результат

| Метрика | До | После |
|---|---|---|
| Load average | 4.04 | 0.15 |
| Free RAM | ~250 MB (с OOM-loop) | 307 MB available |
| Dropbear процессов | 21 | 2 (listener + моя сессия) |
| Outbound SMTP-соединений | 30+ | 0 |
| Counter `incident_block_in 22` | — | растёт (атакующие тыкаются) |

## Постоянные правила (`/etc/nftables.d/99-incident-20260520.nft`)

```nft
chain incident_block_in {
  type filter hook input priority -100; policy accept;
  iifname "eth0" tcp dport 22 counter drop comment "incident-20260520-no-ssh-from-wan"
}
chain incident_block_out {
  type filter hook output priority -100; policy accept;
  oifname "eth0" tcp dport { 25, 465, 587, 2375 } counter drop comment "incident-20260520-block-spam"
  oifname "eth0" tcp dport 22 counter drop comment "incident-20260520-block-ssh-brute"
}
chain incident_block_fwd {
  type filter hook forward priority -100; policy accept;
  oifname "eth0" tcp dport { 25, 465, 587, 2375 } counter drop comment "incident-20260520-block-spam"
  oifname "eth0" tcp dport 22 counter drop comment "incident-20260520-block-ssh-brute"
}
```

SSH доступ остался только через:
- LAN (`192.168.1.0/24`, `br-lan`)
- NetBird (`100.70.207.97`, `wt0`)

## Расширение масштаба: Unifi + NetBird-mesh

Бенелюкс — **не изолированный объект**. Cudy за время взлома имел два открытых вектора в чужие сети:

1. **LAN Бенелюкса (192.168.1.0/24)** — здесь живёт **Unifi-сегмент**: 3 AP/Switch (`70:a7:41:79:ef:29`, `70:a7:41:9a:9e:92`, `70:a7:41:c1:33:0a`). Атакующие, сидя на Cudy под root, имели L2 ко всей подсети — могли сниффить broadcasts, ARP, DHCP. К какому контроллеру эти устройства adopted — на момент расследования не выяснено: inform-трафика ни к LXC 116 НИИКН (`100.70.138.234`), ни к UDM-Pro Знаменского нет. Одно из устройств (`192.168.1.199`, hostname `Benelyuks`) стучится в `192.168.28.34:8381` — это IP не из NetBird, пакеты уходят в default-шлюз провайдера без ответа. Похоже на orphaned-сегмент, см. [[projects/benilux/README#unifi-сегмент-за-cudy]].

2. **NetBird-mesh через wt0** — Cudy получает по NetBird маршруты в:
   - `10.0.0.0/24` (через openclaw — это вся домашняя dttb-инфра)
   - `10.253.1.0/24` + `2.63.246.0/24` + `87.250.251.0/24` + `95.167.245.0/24` (через pve-LionART — ММФБ)
   - `192.168.1.0/24` (через pve-niikn — НИИКН; конфликт с локальной подсетью)
   - `192.168.2.0/24` (Переделки), `192.168.8.0/24`, `192.168.88.0/24`

   Атакующие, имея root на Cudy с активным NetBird agent, теоретически могли достучаться до любого хоста в этих сетях. На практике для этого надо знать топологию (которой у них не было) и проводить активную разведку (не видно в коротких SMTP-сессиях). Но риск ненулевой — особенно для **LXC 116 unifi-controller** (`100.70.138.234:8443`) и **Proxmox НИИКН** (`pve-niikn 100.70.120.229`), которые видны напрямую.

**Что проверить отдельно** (не в этом фиксе):
- Логи Docker LXC 116 unifi-controller (на pve-niikn, `/opt/unifi/config/logs/`) на попытки входа / сессии с `100.70.207.97` за 2026-05-20 13:00–15:45 MSK
- NetBird access policy для группы `OpenWRT VPN` — какие пиры/подсети разрешены этой группе

## Что НЕ сделано (на твоё решение)

1. **Полный wipe / sysupgrade -n.** Малварь была memory-resident (`/tmp/.2424` уже не существовало), бэкдоров на диске не найдено (find -mtime -7 чист в `/etc /lib /sbin /usr/sbin /opt`). Но 100% гарантии чистоты после взлома `root` без переустановки нет. Рекомендую перезалить роутер в течение недели в окно даунтайма.
2. **Жёсткое ограничение dropbear на интерфейсы.** Сейчас он слушает на всех (`0.0.0.0:22`), правило отбрасывает только `iifname eth0`. Можно дополнительно через `uci set dropbear.@dropbear[0].Interface=lan` ограничить bind. Не делал — риск разрыва.
3. **Audit прочих хостов с тем же паролем.** `1qaz!QAZ` фигурирует в инфраструктуре много где (Proxmox, Gitea-WebUI, NPM, Nextcloud, openclaw-LXC, server1c, MikroTik и др.). Также UDM-Pro использует похожий `1qaz!QAZ!QAZ`. **Если хоть один публично-доступный хост с этим паролем существует — он тоже скомпрометирован.** Нужен аудит.
4. **Уведомление abuse.** `45.143.21.60` рассылал спам несколько часов (минимум) — стоит ожидать blocklist-листинги (Spamhaus CSS/XBL, abuseipdb).
5. **Чистка `/var/log/dropbear`** (если есть) — для удаления fingerprint атакующих, но это удалит и улики.

## SMTP forward разблокирован (2026-05-20 ~17:00 MSK)

Александр пожаловался что почта перестала работать — это побочный эффект моего forward-drop для 25/465/587. Снял **forward** chain для этих портов (`/etc/nftables.d/99-incident-20260520.nft`), оставил только output-drop (с самого роутера — там SMTP-клиента быть не должно) + forward-drop для 22 (защита от LAN→WAN SSH-брута, если в сети окажется скомпрометированное устройство). Apple Mail/Outlook у LAN-клиентов снова работает.

## Постоянный фикс (2026-05-20 16:30 MSK)

После исходной изоляции выявлено в UCI: `firewall.@rule[9].name='Allow-SSH-WAN'` — **корневая причина инцидента**, явное разрешение SSH с интернета. Также включён парольный auth: `dropbear.main.PasswordAuth=on`, `RootPasswordAuth=on`. Применено:

```
# backup
cp /etc/config/firewall      /etc/config/firewall.bak.incident-20260520
cp /etc/config/dropbear      /etc/config/dropbear.bak.incident-20260520
cp /etc/dropbear/authorized_keys /etc/dropbear/authorized_keys.bak.incident-20260520

# второй ключ в authorized_keys (recovery, если Mac отвалится)
cat >> /etc/dropbear/authorized_keys <<'KEY'
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKlYObrWNTPQbR+WXMURscQ85Xc5HTLZa+wC8sf8WU72 claude-code@code-server
KEY

# удалить дырявые UCI-правила
uci delete firewall.@rule[<idx>]  # Allow-SSH-WAN
uci delete firewall.@rule[<idx>]  # Allow-IPSec-ESP
uci delete firewall.@rule[<idx>]  # Allow-ISAKMP

# key-only
uci set dropbear.main.PasswordAuth='off'
uci set dropbear.main.RootPasswordAuth='off'

uci commit firewall && uci commit dropbear
fw4 reload && /etc/init.d/dropbear restart
```

**Verify:** вход по ключу — ОК; вход по паролю — `Permission denied (publickey)` (dropbear даже password-prompt не показывает).

## NetBird route — NIIKN остаётся в mesh (2026-05-20 16:50 MSK)

Изначально планировалось убрать route `192.168.1.0/24` от pve-niikn для устранения конфликта. По решению Олега — NIIKN-route в mesh нужен, оставлен (новый id после re-create: `d86ug0rl0ubs73djq120`, peer `cqrj61bl0ubs73dkhq70` pve-niikn).

Сейчас тот же `192.168.1.0/24` анонсируют два пира:
- `d86ug0rl0ubs73djq120` — peer **pve-niikn**, network_id="NIIKN"
- `d7kkgtbl0ubs73du6560` — peer **nbgw-glavtorg**, network_id="Glavtorg-LAN"

Какой именно будет выбран на каждом client-peer — определяется NetBird's внутренней логикой metric/peer-status. Для надёжной работы по конкретному объекту с конфликтующим /24 — ходи по NetBird-IP пира, не по LAN-IP (для Бенелюкса: `100.70.207.97`, для LXC 116 unifi-controller: `100.70.138.234`).

## Улики

Локально на mac: `/tmp/benelux-evidence/`
- `recon.txt` — ps/netstat/dmesg/cron на момент обнаружения
- `lockdown.txt` — лог изоляции (kill 19 сессий)
- `harden.txt` — установка ключа, чистка cron
- `new_password.txt` (chmod 600) — новый root пароль
- `recon.sh`, `lockdown.sh`, `harden.sh`, `finalize.sh` — исполненные скрипты

## Open questions для Олега

- [ ] Audit паролей на других хостах (особенно публично-доступных) — выше
- [ ] Когда планируем wipe+sysupgrade Бенелюкса?
- [ ] Сообщить ли Александру (клиент в КП Бенелюкс) — на объекте только podkop для обхода блокировок, бизнес-сервисов нет, утечки клиентских данных не было; вопрос косметический
- [ ] Кто сделал WAN-SSH публичным изначально? (по умолчанию OpenWrt блокирует ssh на wan)
