Files
knowledge-base/decisions/2026-05-20-benelux-compromise.md
dttb bf565f1392 mmfb/lionart-1c: SSH + фикс efsaveragent + накопленный backlog vault-а
Сегодня (mmfb / LionART 1C):
- projects/mmfb/lionart-1c.md — новый файл: VM 100 на pve LionART
  (WIN-70M2VEJIKEF, 10.253.1.240, Win Server 2022, 1С+SQL+Effector Saver),
  SSH-доступ claude/Kl@udeD1ag!2026 заведён, RDP под Администратор + 2FA.
- projects/mmfb/proxmox-inventory.md — hostname WIN-70M2VEJIKEF в VM 100.
- decisions/2026-05-28-mmfb-effector-saver-locked-admin.md — диагноз
  цикла 7038 (SCM-пароль разъехался с .\Администратор) + lockout учётки,
  и пошаговое решение (disable службы → ADSI unlock → LogonUser-проверка
  → sc.exe config password= → start auto).

Накопившийся backlog (без отдельной правки в эту сессию):
- decisions/: buzharovo (recon, migration-plan, 1c-licensing), sergey
  (instagram iPhone fakeip), amneziavpn macOS v1/v2 incompat, benelux
  compromise 2026-05-20, glavtorg autologon off, omni domain+update.
- projects/: benilux README, buzharovo README+server1c, dttb
  (nextcloud-talk-bot, npm-proxy-hosts, proxmox-inventory, vpn-clients),
  glavtorg, sergey README, projects/_index.
- claude-memory/: benelux, omniroute.
- snippets/mac-dictation/groq-dictate.sh.
- notes/claude/: ~80 авто-сохранённых транскриптов сессий за май.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 12:33:03 +03:00

160 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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:0015: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)