--- 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[] # Allow-SSH-WAN uci delete firewall.@rule[] # Allow-IPSec-ESP uci delete firewall.@rule[] # 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)