mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-07-28 21:17:36 +00:00
docs(antirootkit): design spec — host-IDS process-scanner (auditd) + integrity wrap + alert-only (ref #915)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
This commit is contained in:
parent
aa72f7b209
commit
e420b67fe1
|
|
@ -3,6 +3,13 @@
|
|||
|
||||
---
|
||||
|
||||
## 2026-07-28 — Malware C2 backdoor found + WAN-unreachable saga (U-Boot proves HW OK → Linux mvpp2 driver)
|
||||
|
||||
Long incident session on gk2 (started as a network diag, uncovered a malware persistence, ended isolating the WAN fault to the Linux mvpp2 driver via a U-Boot test).
|
||||
|
||||
- **SECURITY — unauthorized C2 backdoor `notwork-monitoring` (#914).** `/usr/local/bin/notwork-monitoring`, ELF **x86-64** UPX-packed Go 1.24.4, SHA-256 `f2ca2b20…b23dcc`, installed **2026-06-09 00:32** out-of-band (not dpkg, no bash_history/auth.log trace). systemd unit `Restart=always`, `StandardOutput/Error=null` (anti-forensics), beacons `https://5.182.207.11 -insecure -token 9ac1…fb` — C2 = `bunq-helpdesk.dns04.com` (impersonates bunq bank), Frankfurt, **AS213250 ITP-Solutions/Dominic Scholz** (bulletproof). **On gk2 (ARM64) it CANNOT execute** (wrong arch) → crash-loops, never beaconed — and its crash-loop was a big contributor to the boot restart-storm. **Contained:** disabled+quarantined (chmod 000 → `/root/quarantine/`), unit moved to `.evidence`, **nft `output ip daddr 5.182.207.11 drop`**, evidence bundle `/root/notwork-incident-2026-07-27.tar.gz` (transferred off-box over serial base64, SHA verified). Alert doc + Gmail draft to gandalf@gk2.net. **OPEN/URGENT:** amd64 node (192.168.1.9, x86-64 → payload WOULD run) + c3box sweep; initial-access vector ~2026-06-09; confirm `deploy@server` key. Memory `project_notwork_monitoring_c2_incident`.
|
||||
- **NETWORK — WAN unreachable, root cause isolated to Linux.** gk2 lost all external IP: ARP-resolves-but-all-unicast-fails (ICMP/DHCP 100% loss) on **both** eth2 (WAN copper 88E1510) and lan0 (DSA switch). **Systematically ruled OUT everything:** nft (full `flush ruleset` → still dead), tc/DPI/QoS, offloads, conntrack, NAT, ebtables, XDP/eBPF, policy-routing, IP conflict, cold power-cycle, new cable, Freebox reboot, wrong-port. gk2 TX/RX counters increment (0 drop) = hardware seemed fine. **DECISIVE TEST (user's idea): U-Boot.** Interrupted Tow-Boot 2022.07 (ESC/Ctrl+C → boot menu → "Firmware Console"), `setenv ethact mvpp2-2; ping 192.168.1.254` → **`host 192.168.1.254 is alive`**. So the port/PHY (1000baseT FDX)/cable/Freebox are ALL healthy → **the bug is 100% in the Linux mvpp2 driver/stack**, not hardware. **ROOT CAUSE CONFIRMED (2026-07-28): flow-control PAUSE frames block the mvpp2 MAC TX.** `ethtool -S eth2` = `good_octets_sent: 0` (hardware MAC transmits NOTHING, even while software `tx_packets` climbs) + `fc_received: 31796` (gk2 is pause-flooded by the upstream). `ethtool -a` shows `RX: off` configured but `RX negotiated: on` → the HW honors the negotiated pause → TX permanently paused → all unicast dies, RX fine, kernel-independent. U-Boot works because it doesn't negotiate that flow-control. **FIX (confirmed, immediate): `ethtool -A eth2 autoneg off rx off tx off`** → good_octets_sent climbs, arping/ping/DHCP/SSH all restored (0% loss). It's **volatile** (lost on reboot) = exactly the recurring "fixed each time / not in issues" fault the user described. **Made permanent on gk2:** networkd `.link` `10-secubox-eth2-noflowctl.link` (AutoNegotiationFlowControl/RXFlowControl/TXFlowControl=no) + backstop oneshot `secubox-eth2-flowctl-off.service`. Playbook: `docs/FAQ-NETWORK-WAN-RECOVERY.md`. **Dead-ends ruled out** (don't retry): mvpp2 unbind/rebind → `-12 ENOMEM` + removes all NICs; kernel-variant (all 3 fail); cold-boot/new-cable/Freebox-reboot. **Follow-up:** backport `.link`+service into `board/mochabin` for reflash durability (#913); investigate *why* the Freebox floods PAUSE. Memory `project_mochabin_wan_mvpp2_hazard` (also: NEVER `ip link set eth2 down/up` — separate wedge needing cold-boot).
|
||||
|
||||
## 2026-07-27 — fleet-metrics: centralized+meshed node snapshots (trilogy 3/3, #912, deployed gk2)
|
||||
|
||||
Last sub-project of the "auto-centre" trilogy. Each node signs a compact `MetricSnapshot` (vitals + module health + counters) with its sovereign node key into a dedicated last-wins store `/var/lib/secubox/annuaire/fleet/self.json` (NOT the immutable CSPN journal — it can't be pruned); peers pull each other's over the existing `:8799` gondwana mesh read-path (`GET /fleet/self`, public signed, mirrors `/log/export`); `GET /fleet` (JWT) aggregates self + verified peers concurrently (asyncio.gather + to_thread — never blocks the aggregator loop); a `/fleet` panel renders the mesh. Built SDD (5 tasks + opus whole-branch review). `secubox-annuaire 0.10.0`, 424 tests.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,16 @@
|
|||
# TODO — SecuBox-DEB Backlog
|
||||
*Mis à jour : 2026-07-25*
|
||||
*Mis à jour : 2026-07-28*
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Incident 2026-07-28 — malware C2 + WAN mvpp2 (URGENT)
|
||||
|
||||
- [ ] **Sweep IOC malware fleet** (#914) : sur **amd64 secubox-live (192.168.1.9 / 10.10.0.3, x86-64 → la charge TOURNERAIT)** puis **c3box (10.10.0.2)** — chercher `/usr/local/bin/notwork-monitoring`, l'unit `notwork-monitoring.service`, connexions actives vers `5.182.207.11`. SHA-256 `f2ca2b2051c2a98e23b80aab601369474006f6a6dd1dfb8f212f51a726b23dcc`.
|
||||
- [ ] **Vecteur d'accès initial** ~2026-06-09 : qu'exposait gk2 vers Internet ? Revue surface + rotation secrets/clés par prudence. Confirmer la clé `deploy@server` dans `authorized_keys` root.
|
||||
- [ ] **RE de l'échantillon** sur VM x86-64 isolée (`upx -d` + VirusTotal + sandbox) — bundle `/root/notwork-incident-2026-07-27.tar.gz` (+ copie locale scratchpad). Ne JAMAIS exécuter en prod.
|
||||
- [ ] **Détection fleet-wide** : ajouter ces IOC (filename/hash/unit/C2 IP+domaine+ASN) aux règles SecuBox. Signalement abus AS213250 possible.
|
||||
- [ ] **WAN mvpp2** : confirmer le recovery **unbind/rebind `f2000000.ethernet`** (playbook `docs/FAQ-NETWORK-WAN-RECOVERY.md`), puis finaliser **#913** (netplan `.200` statique coexist DHCP, board + `secubox-net-detect`). Rappel : U-Boot pinge OK → HW sain, bug driver Linux.
|
||||
|
||||
## 🧅 Transparent .onion / proxypac — follow-ups fallback WPAD/PAC (2026-07-25, non-bloquant)
|
||||
|
||||
> Le mécanisme **transparent** (primaire, wg-toolbox+LAN) est déployé et couvre le
|
||||
|
|
|
|||
|
|
@ -1,5 +1,20 @@
|
|||
# WIP — Work In Progress
|
||||
*Mis à jour : 2026-07-27*
|
||||
*Mis à jour : 2026-07-28*
|
||||
|
||||
---
|
||||
|
||||
## 🚨 2026-07-28 : Incident gk2 — malware C2 + WAN injoignable (bug driver mvpp2 Linux, prouvé par U-Boot)
|
||||
|
||||
Session incident. Partie d'un diag réseau, a déterré une **backdoor** puis isolé la panne WAN au **driver mvpp2 Linux**.
|
||||
|
||||
- **Malware `notwork-monitoring` (#914)** — backdoor C2 Go x86-64 UPX (SHA `f2ca2b20…`), installée hors-dpkg le **2026-06-09**, beacon `5.182.207.11` (bunq-helpdesk.dns04.com, AS213250 bulletproof). **Inerte sur ARM64** (mauvaise arch → n'a jamais tourné) mais **tournerait sur l'amd64**. Contenue : disable+quarantaine chmod 000 + unit `.evidence` + **nft DROP** + bundle exfiltré en série (SHA vérifié) + alerte + draft Gmail. Mémoire `project_notwork_monitoring_c2_incident`.
|
||||
- **WAN injoignable — cause = driver mvpp2 Linux, PAS le HW.** ARP-résout-mais-tout-unicast-mort (eth2 **et** lan0). Tout le soft éliminé (nft flush total, tc/DPI/offloads/conntrack/NAT/XDP/policy-routing), + cold-boot + câble neuf + reboot Freebox = rien. **Test décisif U-Boot (Tow-Boot)** : `setenv ethact mvpp2-2; ping 192.168.1.254` → **`host is alive`** → port/PHY/câble/Freebox **tous sains**. Playbook : `docs/FAQ-NETWORK-WAN-RECOVERY.md`. Fix candidat = **unbind/rebind mvpp2** (`f2000000.ethernet`) — à confirmer (box en fsck /data après `reboot -f`).
|
||||
|
||||
### ⬜ Next (incident)
|
||||
|
||||
- **Vérifier le recovery** unbind/rebind mvpp2 → rétablir gk2, puis mettre à jour le FAQ avec le résultat confirmé.
|
||||
- **⚠️ Sweep IOC amd64 (192.168.1.9, x86-64 = la charge tournerait) + c3box** (les 2 rebranchés) : `notwork-monitoring` présent ? beacon `5.182.207.11` actif ? Confirmer clé `deploy@server`. Vecteur d'accès ~2026-06-09.
|
||||
- **#913** — fix permanent WAN failover netplan (`.200` statique coexist DHCP, board + `secubox-net-detect`), spec→plan une fois gk2 rétabli.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
132
docs/FAQ-NETWORK-WAN-RECOVERY.md
Normal file
132
docs/FAQ-NETWORK-WAN-RECOVERY.md
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
# FAQ — WAN injoignable sur MOCHAbin (ARP marche, unicast mort)
|
||||
|
||||
*Panne récurrente. Playbook de diagnostic + recovery. Créé 2026-07-28 après une session d'investigation exhaustive.*
|
||||
|
||||
## Symptôme
|
||||
|
||||
gk2 (MOCHAbin, Armada 7040) devient **injoignable sur le LAN/WAN** :
|
||||
- `ping` vers la gateway (`192.168.1.254`) et Internet → **100% de perte**.
|
||||
- `arping <gateway>` → **0 réponse**.
|
||||
- Pas de bail DHCP (aucun `DHCPOFFER`).
|
||||
- **MAIS** : le lien physique est up (`carrier=1`, `Link is Up 1Gbps/Full`), gk2 **reçoit** du broadcast (`rx_packets` monte), et `tx_packets` monte avec `tx_dropped=0`.
|
||||
- Bref : **l'ARP/broadcast semble partir, mais aucun unicast n'aboutit, dans les deux sens.**
|
||||
|
||||
## ⭐ SOLUTION COMPLÈTE (2026-07-28) — 3 problèmes EMPILÉS + watchdog permanent
|
||||
|
||||
Après une longue investigation : ce n'était PAS un seul bug mais **3 problèmes cumulés**, d'où l'échec de tout fix isolé. **Un hub/switch est intercalé entre gk2 et la Freebox.**
|
||||
|
||||
| # | Problème | Symptôme | Fix |
|
||||
|---|---|---|---|
|
||||
| **1** | **Flow-control PAUSE** wedge le TX du MAC mvpp2 | `good_octets_sent=0` (le MAC n'émet rien) | `ethtool -A eth2 autoneg off rx off tx off` |
|
||||
| **2** | **Négociation gigabit MARGINALE** (à cause du hub en face) — le lien accroche au hasard | TX compte mais `.254` muette ; « marche puis KO » | **`ethtool -r eth2` (restart autoneg) en boucle jusqu'à ce que `.254` réponde** (souvent 2-3 essais) |
|
||||
| **3** | **Route `default via lan0` parasite** + `.200` dupliquée sur `lan0` | internet KO alors que `.254` répond ; weak-host ARP | `ip route del default dev lan0` ; `ip addr del 192.168.1.200/24 dev lan0` ; forcer `default via .254 dev eth2` |
|
||||
|
||||
### Preuves décisives
|
||||
|
||||
- **U-Boot pinge `.254`** → HW/PHY/câble OK, bug 100% Linux/L1-négo.
|
||||
- **`ethtool -S eth2` → `good_octets_sent=0`** pendant un ping = TX MAC pausé (couche 1).
|
||||
- **`ethtool -r eth2` × N → `.254` répond au bout de 2-3 essais** = négociation gigabit marginale (couche 2, le hub).
|
||||
- **`ip route` → `default via .254 dev lan0 linkdown`** hijacke le routage (couche 3).
|
||||
|
||||
### Fix permanent installé : `secubox-wan-link-guard`
|
||||
|
||||
Script `/usr/local/sbin/secubox-wan-link-guard` + `secubox-wan-link-guard.service` (au boot) + `.timer` (toutes les 30s). À chaque passage, idempotent et non-disruptif quand tout va bien :
|
||||
1. `ethtool -A eth2 autoneg off rx off tx off` (couche 1)
|
||||
2. supprime la route/IP `lan0` parasite + force `default via .254 dev eth2` (couche 3)
|
||||
3. si `.254` ne répond pas → **`ethtool -r eth2` en boucle (max 6)** jusqu'à accroche (couche 2)
|
||||
|
||||
⚠️ **La VRAIE cause racine physique = le hub/switch intercalé** qui rend la négo gigabit marginale. Le watchdog est un contournement software efficace ; le fix propre serait de **retirer le hub** (gk2 direct sur la Freebox) ou le remplacer par un switch gigabit correct. Mais le watchdog maintient gk2 en ligne sans intervention.
|
||||
|
||||
---
|
||||
|
||||
## Détail couche 1 — flow-control (cause racine — CONFIRMÉE 2026-07-28) ✅
|
||||
|
||||
**Le flow-control (PAUSE frames) bloque le TX du MAC mvpp2 de gk2.** Preuve irréfutable via `ethtool -S eth2` :
|
||||
|
||||
```
|
||||
good_octets_received: 787531 ← RX marche
|
||||
good_octets_sent: 0 ← le MAC hardware n'émet AUCUN octet (reste 0 même pendant un ping)
|
||||
fc_received: 31796 ← gk2 reçoit un FLOT de PAUSE frames (flow-control)
|
||||
```
|
||||
|
||||
Le compteur logiciel `tx_packets` monte (le kernel croit émettre) mais le **compteur matériel `good_octets_sent` reste bloqué à 0** : le MAC est mis en **pause permanente** par les PAUSE frames reçues → rien n'atteint le fil → tout unicast (ARP/ICMP/DHCP) meurt, RX intact. Kernel-**indépendant** (les 3 variantes 6.6.137 / 6.12.85 échouent). **U-Boot marche** car il ne négocie pas ce flow-control (cf. test plus bas).
|
||||
|
||||
**Incohérence révélatrice** : `ethtool -a eth2` montre `RX: off` (configuré) mais `RX negotiated: on` — le HW honore quand même la pause négociée par autoneg.
|
||||
|
||||
### ✅ LE FIX (confirmé, immédiat)
|
||||
|
||||
```bash
|
||||
ethtool -A eth2 autoneg off rx off tx off
|
||||
```
|
||||
|
||||
Effet immédiat vérifié : `good_octets_sent` se met à monter, `arping 192.168.1.254` répond, `ping` = 0% perte. **C'est volatile** (perdu au reboot) → d'où la récurrence (« résolu à chaque fois » = ré-appliqué à la main). Rendu **permanent** (voir plus bas).
|
||||
|
||||
⚠️ **NE JAMAIS** faire `ip link set eth2 down; up` — ça **wedge** en plus le port mvpp2/comphy (état différent, qui lui exige un cold-boot). Voir mémoire `project_mochabin_wan_mvpp2_hazard`.
|
||||
|
||||
*(Question ouverte : pourquoi la Freebox floode-t-elle des PAUSE frames vers gk2 ? — port Freebox, duplex, ou congestion. Non bloquant : ignorer la pause côté gk2 suffit. À creuser si ça revient malgré le fix permanent.)*
|
||||
|
||||
## Ce qui NE sert à RIEN (déjà éliminé, ne pas reperdre du temps dessus)
|
||||
|
||||
- `nft flush ruleset` complet (le pare-feu n'y est pour rien)
|
||||
- offloads (`ethtool -K` off), conntrack (jamais plein), NAT, ebtables, XDP/eBPF, policy-routing (`ip rule`)
|
||||
- conflit d'IP (`arping -D` = pas de doublon)
|
||||
- **cold power-cycle** complet (débranchage secteur ≥30s) → ne corrige PAS
|
||||
- **câble neuf**, **autre port**, **reboot Freebox** → ne corrigent PAS
|
||||
- changer d'IP (.210), passer le câble sur un port LAN (lan0) → même échec
|
||||
|
||||
## Test décisif : U-Boot (tranche HW vs Linux en 2 min)
|
||||
|
||||
Le bootloader est **Tow-Boot 2022.07**. Via la console série (`/dev/ttyUSB0`, 115200 8N1) :
|
||||
|
||||
1. Reboot : `sync; sync; reboot -f` (le `-f` évite le hang unmount du SSD USB `/data` ; sinon `reboot` peut se bloquer 180s sur `sd [sdb] timing out`).
|
||||
2. **Interrompre l'autoboot** : spammer **ESC** (`\x1b`) ou **Ctrl+C** dès l'apparition d'U-Boot (PAS ENTER — ENTER sélectionne un noyau dans le menu).
|
||||
3. Dans le menu boîte : descendre (flèche bas `\x1b[B` ×7) jusqu'à **« Firmware Console »** → ENTER → prompt `=>`.
|
||||
4. Mapping U-Boot : `eth0=mvpp2-0, eth1=mvpp2-1 [PRIME], eth2=mvpp2-2`. Le câble WAN = **eth2 = mvpp2-2**.
|
||||
5. Tester :
|
||||
```
|
||||
setenv ipaddr 192.168.1.200
|
||||
setenv netmask 255.255.255.0
|
||||
setenv gatewayip 192.168.1.254
|
||||
setenv ethact mvpp2-2
|
||||
ping 192.168.1.254
|
||||
```
|
||||
- `host 192.168.1.254 is alive` → **HW sain, bug Linux** (cas nominal de cette panne).
|
||||
- échec → alors seulement suspecter câble/port/Freebox.
|
||||
6. Retour Linux : `boot` (ou `run bootcmd`).
|
||||
|
||||
Note : `Net: Requested port mode (25) not supported` / `Wrong port mode (25)` dans U-Boot = le **cage SFP+ 10G vide** (Comphy-4 SFI0), **normal**, sans rapport avec eth2.
|
||||
|
||||
## Fix permanent (installé 2026-07-28)
|
||||
|
||||
Deux mécanismes pour que `ethtool -A eth2 autoneg off rx off tx off` survive au reboot :
|
||||
|
||||
1. **networkd `.link`** (natif, appliqué par udevd dès l'apparition d'eth2 — couvre le DHCP au boot) — `/etc/systemd/network/10-secubox-eth2-noflowctl.link` :
|
||||
|
||||
```ini
|
||||
[Match]
|
||||
OriginalName=eth2
|
||||
|
||||
[Link]
|
||||
AutoNegotiationFlowControl=no
|
||||
RXFlowControl=no
|
||||
TXFlowControl=no
|
||||
```
|
||||
|
||||
2. **Service systemd backstop** (garanti, commande exacte) — `/etc/systemd/system/secubox-eth2-flowctl-off.service`, `Type=oneshot`, `ExecStart=/sbin/ethtool -A eth2 autoneg off rx off tx off`, `enable`d sur `multi-user.target`.
|
||||
|
||||
⚠️ **NE PAS** tenter unbind/rebind du driver (`/sys/bus/platform/drivers/mvpp2/{unbind,bind}`) : le re-probe **échoue en `-12 ENOMEM`** (mémoire DMA fragmentée après le boot) et **supprime TOUS les netdevs mvpp2** (eth1/eth2 + switch lan0-3) → box sans réseau, reboot obligatoire. Testé, à proscrire.
|
||||
|
||||
### À faire — durcir dans la source (pas encore fait)
|
||||
|
||||
Le fix ci-dessus est **live sur gk2**. Pour la durabilité inter-reflash, backporter le `.link` + le service dans le paquet board (`board/mochabin/` + `secubox-net-detect`) — cf. **#913**. Tant que ce n'est pas fait, un reflash/réinstall perd le fix.
|
||||
|
||||
## Config attendue
|
||||
|
||||
- WAN = `eth2` (câble sur le port WAN isolé), `192.168.1.200/24`, gw `192.168.1.254`, DHCP.
|
||||
- Piège récurrent : au boot la route par défaut se recolle parfois sur **`lan0` (linkdown)** alors que le câble est sur eth2 → corriger : `ip route replace default via 192.168.1.254 dev eth2`. Le masquerade LXC doit viser la vraie iface WAN (`oif eth2 masquerade`) — cf. HISTORY:2509.
|
||||
- Fix permanent en cours : **#913** (netplan `.200` statique coexistant avec DHCP, board + `secubox-net-detect`).
|
||||
|
||||
## Accès de secours
|
||||
|
||||
- Console série : `minicom -D /dev/ttyUSB0` (ou `ssh`/`cat` sur `/dev/ttyUSB0`), 115200 8N1. Login `root` / `secubox`.
|
||||
- SSH normal (quand le réseau marche) : `ssh root@192.168.1.200` (clé).
|
||||
99
docs/superpowers/specs/2026-07-28-antirootkit-design.md
Normal file
99
docs/superpowers/specs/2026-07-28-antirootkit-design.md
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
# secubox-antirootkit — Design (host-IDS / anti-rootkit)
|
||||
|
||||
*Issue #915. Né de l'incident #914 (backdoor C2 `notwork-monitoring` restée ~7 semaines non détectée).*
|
||||
|
||||
## Objectif
|
||||
|
||||
Détecter, alerter et **préparer** la neutralisation des persistances non autorisées type C2/trojan sur un hôte SecuBox, en distinguant automatiquement le légitime (paquet dpkg signé) du malveillant (hors-paquet + comportement suspect). Répondre instantanément à « **ce process est-il légitime ?** » — la question que l'incident #914 et la confusion YaCy/threat-analyst ont rendue concrète.
|
||||
|
||||
## Décisions validées (brainstorming)
|
||||
|
||||
- **Home + base de détection** : nouveau paquet Debian `secubox-antirootkit` qui **orchestre des outils éprouvés** (`debsums`, `aide`, `rkhunter`, `chkrootkit`) + une **couche SecuBox** (heuristiques C2, baseline, alerte mesh, préparation quarantaine).
|
||||
- **Posture de réponse** : **alerte SEULE — jamais d'auto-neutralisation.** Le module détecte, alerte, et *prépare* la commande de quarantaine ; l'opérateur valide chaque neutralisation. (Justifié : gk2 a 200+ services ; un faux positif auto-neutralisé casserait du légitime.)
|
||||
- **Traçage des exec (cœur du process scanner)** : **auditd** (`-S execve`), qui logue chaque exec **tenté ET réussi/échoué** (forensic, standard CSPN).
|
||||
|
||||
## Prérequis (bloquant install, dette existante)
|
||||
|
||||
Sur gk2, `apt install` échoue (deps cassées : `secubox-ndpid`/`secubox-netifyd`/`secubox-p2p`/`secubox-rtty` → `ndpid`/`netifyd`/`python3-aiohttp`/`rtty` introuvables) **et `/boot` est plein à 100%**. Le module dépend de `auditd`, `debsums`, `aide`, `rkhunter`, `chkrootkit` → **réparer l'état apt + nettoyer `/boot` est un prérequis** avant déploiement. À traiter hors périmètre de ce module (tâche de maintenance).
|
||||
|
||||
## Architecture
|
||||
|
||||
Paquet `secubox-antirootkit` : daemon Python + API FastAPI sur socket Unix `/run/secubox/antirootkit.sock` (pattern SecuBox aggregator-served). Trois sous-systèmes isolés, chacun avec une responsabilité et une interface claires.
|
||||
|
||||
### A. Process Scanner (cœur — priorité v1) — via auditd
|
||||
|
||||
**Responsabilité** : ne rien laisser s'exécuter (ni *tenter* de s'exécuter) sans trace, et alerter sur les exec anormaux.
|
||||
|
||||
- **Règle auditd** livrée dans `/etc/audit/rules.d/99-sbx-procwatch.rules` :
|
||||
```
|
||||
-a exit,always -F arch=b64 -S execve -k sbx_exec
|
||||
-a exit,always -F arch=b32 -S execve -k sbx_exec
|
||||
```
|
||||
(Alternative bas-volume si nécessaire : watches ciblées `-w /usr/local/bin -p x`, `/tmp`, `/dev/shm`, `/opt`, `/usr/lib/jvm` — voir §Perf.)
|
||||
- **Daemon `sbx-procwatchd`** lit le flux audit (via `auditd` + `ausearch`/`aureport`, ou socket `audispd`) et enregistre chaque exec dans une base **SQLite append-only** `/var/lib/secubox/antirootkit/execlog.db` : `ts, pid, ppid, uid, exe, argv, cwd, success (yes/no), exit, key, dpkg_pkg (nullable)`.
|
||||
- **Champ `dpkg_pkg`** résolu par `dpkg -S <exe>` (mis en cache) → **la réponse « légitime ? » = `dpkg_pkg IS NOT NULL`**. (YaCy → `secubox-yacy` ✓ ; threat-analyst → `secubox-threat-analyst` ✓ ; `notwork-monitoring` → NULL ✗.)
|
||||
- **Heuristiques d'alerte** (score, pas de kill) :
|
||||
- exec d'un binaire **hors-dpkg** depuis `/usr/local/bin|sbin`, `/tmp`, `/dev/shm`, `/opt`, `$HOME` ;
|
||||
- **exec en échec répété** (`success=no` récurrent pour le même exe) = signature crash-loop (`notwork` tentait toutes les 10s et échouait sur l'arch) ;
|
||||
- exe hors-dpkg **+ connexion sortante** (corrélation avec `secubox-netstats`/conntrack) ;
|
||||
- exe dont l'unit systemd a `Restart=always` **+** `StandardOutput/Error=null` (logs silencés).
|
||||
|
||||
### B. Integrity Scanner (wrap outils — v1 léger)
|
||||
|
||||
**Responsabilité** : intégrité des fichiers et points de persistance.
|
||||
|
||||
- Orchestre en tâche planifiée (timer) : `debsums -c` (fichiers dpkg altérés), `aide --check` (baseline signée `/var/lib/secubox/antirootkit/aide.db`), `rkhunter --check --sk` + `chkrootkit` (signatures connues).
|
||||
- Surveille les **points de persistance** : `/usr/local/{bin,sbin}` (fichiers hors-dpkg), units systemd (`Restart=always` + logs null + `ExecStart` hors-dpkg), `~/.ssh/authorized_keys` (clés inconnues vs baseline), crontabs, `/etc/ld.so.preload`, `/etc/systemd/system/*.timer`.
|
||||
- Baseline signée (clé nœud, comme les autres modules SecuBox) → dérive = alerte.
|
||||
|
||||
### C. Alerte + Préparation-quarantaine (alerte SEULE)
|
||||
|
||||
**Responsabilité** : notifier et outiller l'opérateur, sans jamais agir seul.
|
||||
|
||||
- **Alerte** : émet vers `secubox-soc` (agrégateur), mail, et `threatmesh` (mesh). Enrichit avec match **IOC connus** (feed `secubox-cyberfeed`/`secubox-threatmesh` : hash/IP/domaine/ASN — incluant les IOC #914 : `notwork-monitoring`, `5.182.207.11`, AS213250).
|
||||
- **Préparation quarantaine** (jamais exécutée automatiquement) : pour une menace confirmée, prépare et présente dans le SOC la séquence — `chmod 000` + copie horodatée + `sha256` + bundle de preuves + `nft output ip daddr <C2> drop` + `systemctl disable` de l'unit — **derrière un bouton de validation opérateur**.
|
||||
- **Panneau webui** `/antirootkit` (pattern WEBUI-PANEL-GUIDELINES) : timeline des exec (qui/quoi/quand/où/parent), verdict légitime/suspect par ligne, état des scans intégrité, file d'alertes avec bouton « quarantiner » (validation manuelle).
|
||||
|
||||
## Flux de données
|
||||
|
||||
```
|
||||
auditd (execve) ─┐
|
||||
aide/debsums/rk ─┼─→ sbx daemon ─→ SQLite append-only ─→ moteur de règles ─┬─→ alerte SOC/mail/mesh
|
||||
authorized_keys ─┘ (résolution dpkg, score) └─→ bouton quarantaine (manuel)
|
||||
└─→ API/panneau /antirootkit
|
||||
```
|
||||
|
||||
## Gestion d'erreurs
|
||||
|
||||
- auditd absent/cassé → le module démarre en **mode dégradé** (scan intégrité seul) + alerte « process-scan indisponible » (ne bloque pas le boot).
|
||||
- `dpkg -S` lent → cache mémoire + persistant.
|
||||
- Base SQLite corrompue → recrée + alerte, ne perd pas le daemon.
|
||||
- Volume audit élevé → bascule automatique sur watches ciblées (§Perf) + rotation.
|
||||
|
||||
## Performance
|
||||
|
||||
- La règle `-S execve` globale est **volumineuse** sur une box à 200+ services (health-checkers spawnent en continu). v1 : **watches ciblées** sur les chemins à risque (`/usr/local/{bin,sbin}`, `/tmp`, `/dev/shm`, `/opt`, `/usr/lib/jvm`) + rotation `audit.log`. La règle globale reste une **option** (config TOML `procwatch.mode = targeted|full`).
|
||||
- Double-cache (pattern SecuBox) pour l'API stats du panneau.
|
||||
|
||||
## Tests
|
||||
|
||||
- **Rejeu du profil #914** : binaire hors-dpkg dans `/usr/local/bin` + unit `Restart=always` + `Standard*=null` + (simulateur de) beacon → **doit lever une alerte FORTE** et apparaître comme non-dpkg dans l'execlog.
|
||||
- **Non-régression légitime (0 faux positif)** : YaCy (`secubox-yacy`, java) + `secubox-threat-analyst` (Python) → **verdict légitime** (dpkg-backed), aucune alerte, jamais quarantinés.
|
||||
- **Crash-loop** : unit qui échoue à l'exec en boucle → détecté via `success=no` récurrent.
|
||||
- **Intégrité** : altérer un fichier dpkg → `debsums` le détecte ; ajouter une clé à `authorized_keys` → dérive baseline détectée.
|
||||
- **Alerte-seule** : vérifier qu'aucune neutralisation n'est jamais exécutée sans validation.
|
||||
- Tests repo `.venv`, per-directory (pytest.ini).
|
||||
|
||||
## Hors périmètre (v1)
|
||||
|
||||
- Auto-neutralisation (posture = alerte seule).
|
||||
- eBPF (auditd retenu ; eBPF = évolution possible v2 pour le sub-ms live).
|
||||
- Sweep fleet inter-nœuds (le module est host-local ; la fédération passe par `threatmesh`/SOC existants).
|
||||
- Réparation de l'état apt / `/boot` (prérequis de maintenance, hors module).
|
||||
|
||||
## Invariants SecuBox
|
||||
|
||||
- **Jamais root in-process** pour les actions : le daemon tourne sous `secubox-antirootkit` ; les actions root (quarantaine) passent par un `ctl` scoped-sudo validé opérateur (pattern `feedback_webui_delegates_to_confined_ctl`).
|
||||
- Journal execlog **append-only** (posture CSPN).
|
||||
- Jamais de chown des parents partagés (`/run/secubox`, `/var/lib/secubox`).
|
||||
- Alerte-seule = aucune action destructive automatique.
|
||||
Loading…
Reference in New Issue
Block a user