Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
SPiCa — Détecteur de rootkit Linux basé sur eBPF utilisant une analyse multi-canal à vues croisées (sched_switch, NMI, /proc) pour détecter DKOM, la falsification de points de trace et le masquage de processus avec vérification d'intégrité au niveau matériel. | Kitploit
Outils/GitHubGitHub/0xkirisame/spica
Outils DéfensifsGestion des Indicateurs de Compromission (IOC)Analyse ForensiqueAnalyse de MalwareAnalyse de BinairesDétection d'IntrusionArticles et RechercheApprentissage et ÉducationRéponse aux IncidentsDétection d'Anomalies
GitHub0xkirisame/spica
1046il y a 1 moisVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

SPiCa

Détecteur de rootkit Linux basé sur eBPF utilisant une analyse multi-canal à vues croisées (sched_switch, NMI, /proc) pour détecter DKOM, la falsification de points de trace et le masquage de processus avec vérification d'intégrité au niveau matériel.

Voir le dépôt

SPiCa

Intégrité des processus système et analyse multi-vues

SPiCa

« Je vais chanter, alors brille, SPiCa... »

SPiCa est un détecteur de rootkits Linux basé sur eBPF, écrit en Rust. Le nom provient de la chanson de Hatsune Miku SPiCa et de l'étoile qu'elle évoque — Spica (Alpha Virginis), le point le plus brillant de la Vierge. Ce qui ressemble à une étoile unique à l'œil nu est en réalité une binaire spectroscopique : deux étoiles en orbite mutuelle, impossibles à distinguer comme objets séparés sans mesurer leur spectre. SPiCa applique le même principe à l'observation du noyau : plusieurs canaux indépendants mesurent le même état du noyau depuis des mécanismes physiquement distincts, et un rootkit qui en supprime un est exposé par les autres.

Avertissement : Une partie significative de cette base de code a été générée ou refactorisée avec l'aide de GLM. Des tests rigoureux et une conception itérative ont été appliqués, mais examinez le code pour la sécurité et les performances avant toute utilisation en production.


Table des matières

  1. Modèle de menace
  2. Aperçu de l'architecture
  3. Le canal d'observation sched_switch
  4. Le canal d'intégrité NMI
  5. Logique de détection
  6. Secret d'adresse limité par le vérifieur
  7. Porte d'accès aux cartes LSM
  8. Gestion des clés et obscurcissement
  9. Scellement TPM lié au PCR (Conception)
  10. Défense en profondeur
  11. L'incident du bug BTF
  12. Limitations connues et surface d'attaque
  13. Construction et exécution
  14. Feuille de route
  15. Glossaire

1. Modèle de menace

L'adversaire contraint : le rootkit eBPF

SPiCa est conçu pour vaincre l'adversaire contraint par eBPF — un attaquant disposant de privilèges élevés (CAP_BPF ou CAP_SYS_ADMIN) qui charge un programme eBPF privilégié dans le noyau. Cet adversaire est fondamentalement plus faible qu'un rootkit LKM car le vérifieur BPF impose des contraintes strictes :

Avec les LKM bloqués par la porte LSM après le démarrage, cet adversaire contraint est la menace réaliste restante. Le mécanisme anti-contournement de SPiCa est calibré pour cette menace — chaque défense est honnête sur ce qu'elle couvre et ce qu'elle ne couvre pas.

Non-objectifs

  • Exploits de noyau par un État-nation — corruption mémoire permettant une écriture arbitraire dans le noyau sans init_module. SPiCa élève le niveau en bloquant le vecteur LKM le plus simple, mais ne plafonne pas l'adversaire.
  • LKMs hostiles chargés avant le démarrage de SPiCa — une défense en profondeur (Secure Boot, signature des modules, IMA) est requise pour la fenêtre de démarrage.
  • Exploits du vérifieur — si le vérifieur BPF est incorrect (CVE historiques : CVE-2020-27194, CVE-2022-23222, CVE-2023-2163), l'adversaire échappe au modèle contraint pour une exécution de code arbitraire dans le noyau. Il s'agit d'une classe de menace distincte. Les défenses de SPiCa tiennent sous un vérifieur correct.

SPiCa est la couche de dernier recours dans une pile de défense en profondeur, pas un substitut pour les couches supérieures.


2. Aperçu de l'architecture

SPiCa exécute quatre programmes eBPF attachés à des hooks du noyau, plus un moteur de détection en espace utilisateur qui corrèle leurs sorties avec la vue qu'a le système de lui-même (/proc).

Trois canaux d'observation, chacun supprimable uniquement par un mécanisme de coût croissant

La propriété architecturale clé : un rootkit ne peut pas supprimer les trois canaux simultanément sans que la suppression elle-même devienne détectable ou déstabilisatrice. Supprimer le NMI nécessite de patcher l'IDT (table des descripteurs d'interruption), ce qui provoque une panique sur la plupart des noyaux. C'est la « bombe vivante » — la seule voie de l'attaquant vers la cécité totale est celle qui fait probablement planter le système.

Modèle de détection — trois phrases```

sched sees it, /proc doesn't → DKOM NMI finds sched's heartbeat stopped → TAMPER sched goes globally silent, /proc != empty → SILENT

root@kitploit:~
Chaque classe de détection est un verdict différentiel : une divergence entre deux ou plusieurs canaux. Le moteur de détection est une fonction pure sur le registre + instantané /proc + horodatages des canaux — pas d'E/S, pas d'effets secondaires, entièrement testable unitairement.

### La refonte du NMI : de l'observation à l'intégrité

Dans la conception originale, le NMI était un second canal d'observation des processus qui échantillonnait le CPU et rapportait quelle tâche était en cours d'exécution. C'était redondant : sched_switch observe déjà l'ordonnancement, et le NMI échantillonnait les mêmes données via un mécanisme différent. La redondance coûtait environ 1000+ événements de tampon en anneau par seconde par CPU de données de processus qui, 99,999 % du temps, confirmaient « oui, l'ordonnanceur fait ce que l'ordonnanceur fait ».

Dans l'architecture repensée, **le NMI est réutilisé de l'observation des processus vers la vérification d'intégrité des tracepoints.** Il ne rapporte plus quel processus est sur le CPU. Au lieu de cela, il vérifie que `sched_switch` est effectivement en cours d'exécution en lisant un heartbeat partagé `.bss`. Cela :

1. Élimine environ 99 % du trafic du tampon en anneau NMI (événements quasi nuls en régime permanent)
2. Détecte directement le détachement, la suppression et les échecs d'attachement BTF des tracepoints (le bug BTF original — voir [§11](#11-the-btf-bug-incident))
3. S'exécute depuis une interruption matérielle, en dehors du chemin de distribution des tracepoints — immunisé contre `bpf_override_return`, l'interception kprobe et la manipulation du tableau de fonctions
4. Lit les globales `.bss` via un accès mémoire direct, pas via les helpers BPF — immunisé contre `fmod_ret` sur les fonctions helpers

## 3. Le canal d'observation sched\_switch

Un programme eBPF attaché au tracepoint `sched_switch` se déclenche chaque fois que le noyau ordonnance un processus sur un CPU. Il lit le PID et le comm de la tâche entrante directement depuis les arguments du tracepoint en utilisant des lectures traditionnelles (non-BTF) à décalage fixe :```
ctx.read_at::<u32>(56)    → next_pid
ctx.read_at::<[u8;16]>(40) → next_comm

Délibérément pas BTF/CO-RE. La disposition des arguments des tracepoints est stable à travers les versions du noyau (elle fait partie de l’ABI des tracepoints). Utiliser des décalages codés en dur évite la fragilité liée aux versions du noyau qu’entraînerait la navigation de structures résolue par BTF. C’est un choix de conception délibéré documenté dans §11.

À chaque invocation, le programme :

  1. Lit next_pid et next_comm depuis le contexte du tracepoint
  2. Filtre la tâche idle (PID 0)
  3. XOR-obfusque la structure ProcessInfo avec BASE_KEY
  4. Soumet au tampon circulaire sc_sched
  5. Écrit bpf_ktime_get_ns() dans la globale .bss SCHED_HEARTBEAT — le heartbeat que le vérificateur d’intégrité NMI surveille

Le programme évite délibérément bpf_get_current_pid_tgid() dans ce contexte. Au moment de sched_switch, "current" est la tâche sortante, pas celle entrante. Les arguments du tracepoint fournissent l’identité de processus correcte (entrante).

Discipline de la base de temps

Le moteur de détection utilise une seule base de temps monotone : nanosecondes depuis le démarrage du processus SPiCa (Instant::now() depuis l’entrée de run_detection()). Lorsqu’un événement sched arrive, le gestionnaire d’événements stocke le now fourni par l’appelant (nanosecondes locales au processus), pas la valeur eBPF bpf_ktime_get_ns() intégrée dans l’événement. Cela évite le décalage de base de temps qui se produirait si le temps de démarrage du noyau était mélangé avec le temps local du processus — un bogue présent dans les versions antérieures et qui faisait échouer silencieusement tous les prédicats de vivacité.


4. Le Canal d’Intégrité NMI

Conception : heartbeat .bss, pas de BTF, pas de parcours de structures noyau

Le programme NMI est attaché à un compteur perf matériel (HW_CPU_CYCLES) qui se déclenche au niveau d’interruption matériel. Les NMI ne peuvent pas être désactivées avec cli — les supprimer nécessite de reprogrammer le PMU ou de hooker l’IDT, deux actions bruyantes et déstabilisantes.

Le mécanisme de vérification d’intégrité est d’une simplicité absolue :``` .bss (shared within SPiCa's ELF object — all programs see the same memory): SCHED_HEARTBEAT ← written by sched_switch on every invocation NMI_LAST_HB ← NMI's record of the last heartbeat it observed NMI_FIRST_TICK ← first NMI invocation timestamp (grace period reference) NMI_LAST_EMIT ← throttle: last event emission timestamp

sched_switch runs → SCHED_HEARTBEAT = bpf_ktime_get_ns()

NMI fires (once per second, throttled): if SCHED_HEARTBEAT == NMI_LAST_HB: if past grace period (5 seconds since first NMI tick): → sched_switch stopped running → emit event_type=1 (TAMPER) else: → sched_switch is alive → emit event_type=0 (heartbeat OK) NMI_LAST_HB = SCHED_HEARTBEAT

root@kitploit:~
### Pourquoi cela détecte toutes les attaques dans le périmètre

| Attack | Ce qui se produit | Ce que NMI voit |
|---|---|---|
| Tracepoint détaché du tableau funcs | sched\_switch cesse de s'exécuter | `SCHED_HEARTBEAT` se fige → TAMPER |
| Bogue BTF / échec d'attachement (silencieux) | sched\_switch ne s'exécute jamais | `SCHED_HEARTBEAT` reste à 0 → TAMPER (après délai de grâce) |
| `bpf_override_return` sur une fonction du planificateur | Si elle empêche le tracepoint de se déclencher | `SCHED_HEARTBEAT` se fige → TAMPER |
| Bytecode modifié en place | Nécessite une écriture arbitraire dans le noyau (niveau LKM) | En dehors du modèle de menace eBPF |
| Pointeur consommateur du ring buffer manipulé | Les événements sched n'atteignent pas l'espace utilisateur | `SCHED_HEARTBEAT` avance toujours (le programme s'exécute) → pas de faux TAMPER ; l'espace utilisateur détecte via `max(sched_last)` obsolète → SILENT |

### Pourquoi `.bss` spécifiquement

Les globales `.bss` sont stockées dans la section de données interne du programme BPF, soutenue par une map de tableau interne gérée par le chargeur. Elles sont :

- **Non pinables séparément** — elles n'apparaissent pas comme des maps nommées dans `/sys/fs/bpf/`
- **Non interceptables via les hooks `bpf_map_update_elem`** — les écritures `.bss` sont des stockages mémoire directs, pas des appels système de mise à jour de map. L'ancien mécanisme `sc_canary` (comparant une copie `.bss` avec une copie de map nommée pour détecter l'interception de `bpf_map_update_elem`) n'est plus nécessaire.
- **Partagées entre les programmes dans le même objet ELF** — sched\_switch et NMI communiquent via `.bss` sans interface externe

### Immunité contre l'interception basée sur BPF

Le vérificateur d'intégrité NMI est structurellement immunisé contre les attaques de remplacement BPF en raison d'une propriété fondamentale : `bpf_override_return` intercepte les **appels** de fonction, mais le vérificateur NMI n'*appelle* pas les éléments qu'il vérifie — il *lit directement la mémoire `.bss`*. Vous ne pouvez pas remplacer la valeur de retour d'une lecture mémoire car une lecture mémoire n'est pas un appel de fonction.

De plus :
- `bpf_probe_read_kernel` (utilisé pour les lectures de structures noyau dans des conceptions alternatives) est un helper sécurisé qui accepte toute adresse — mais la conception du heartbeat `.bss` de SPiCa n'en a même pas besoin. Le vérificateur lit les globales `.bss` via des instructions de chargement directes.
- Le programme NMI s'exécute dans un contexte NMI, où les kprobes sont structurellement peu fiables (le noyau les diffère ou les supprime). Une attaque basée sur kprobe contre l'exécution du vérificateur lutte contre le matériel.

### Sémantique des événements NMI

Le ring buffer NMI (`sc_nmi`) transporte des événements légers :

| `event_type` | Signification | Action de l'espace utilisateur |
|---|---|---|
| 0 | Heartbeat — NMI en vie, sched\_switch en vie | Mettre à jour le timestamp `last_nmi_heartbeat` |
| 1 | TAMPER — NMI en vie, heartbeat de sched\_switch gelé | Afficher `[TAMPER]` immédiatement |

Les événements sont émis au maximum une fois par seconde (limité par `NMI_LAST_EMIT`). Si le ring buffer NMI devient silencieux pendant >5 secondes, l'espace utilisateur déclenche `[SILENT]` — le canal NMI lui-même est mort.

---

## 5. Logique de détection```mermaid
graph TD
    subgraph RING0["Kernel Space: Four eBPF Programs"]
        direction TB
        SCHED_P["TracePoint, sched_switch<br/>read next_pid, next_comm<br/>write SCHED_HEARTBEAT (.bss)<br/>XOR obfuscate → sc_sched"]
        NMI_P["PerfEvent hardware NMI<br/>read SCHED_HEARTBEAT (.bss)<br/>compare to NMI_LAST_HB<br/>frozen → event_type=1 (TAMPER)<br/>alive → event_type=0 (heartbeat)<br/>→ sc_nmi"]
        LSM_P["BPF LSM, kernel_read_file<br/>READING_MODULE<br/>gate=0: allow + log<br/>gate=1: EPERM + log → sc_lsm"]
        WATCH_P["TracePoint, sched_process_exit<br/>current == SPICA_PID (.bss)? → sc_wd flag"]
    end

    subgraph RING3["User Space: Differential Engine"]
        ENGINE["SPiCa (Tokio async)"] -->|XOR deobfuscate| RB_S[(sc_sched RingBuf)]
        ENGINE -->|event_type=0: heartbeat<br/>event_type=1: TAMPER| RB_N[(sc_nmi RingBuf)]
        ENGINE -->|raw read| RB_L[(sc_lsm RingBuf)]
        ENGINE -->|read_dir| PROC[" /proc"]
        RB_S --> FSM{Detection FSM}
        PROC --> FSM
        FSM -->|scheduled, absent /proc, >2s| D1["[DKOM]"]
        FSM -->|in /proc, never seen by sched, >5s| D2["[GHOST]"]
        RB_N -->|event_type = 1| D3["[TAMPER]"]
        FSM -->|sched channel silent, /proc ≠∅| D4["[SILENT]"]
        FSM -->|raw getdents64 ≠ libc readdir| D9["[HOOK]"]
        RB_S -->|same TGID, different start_time_ns| D5["[DUPE]"]
        RB_L -->|allowed = 1| D7["[LKM-ALLOW]"]
        RB_L -->|allowed = 0| D8["[LKM-DENY]"]
        WATCH_P -.->|pin exists at startup| D6["[WATCHDOG]"]
    end

    classDef kernbox  fill:#fdf2f8,stroke:#9333ea,stroke-width:2px,color:#581c87;
    classDef userbox  fill:#eff6ff,stroke:#2563eb,stroke-width:2px,color:#1e3a8a;
    classDef alertbox fill:#fff7ed,stroke:#ea580c,stroke-width:1px,color:#7c2d12;
    classDef storage  fill:#f8fafc,stroke:#64748b,stroke-width:1px;
    class RING0 kernbox;
    class RING3 userbox;
    class D1,D2,D3,D4,D5,D6,D7,D8,D9 alertbox;
    class RB_S,RB_N,RB_L,PROC storage;

Détection SILENT au niveau du canal

SILENT est un verdict au niveau du canal, pas par processus. Il se déclenche lorsque :

  1. Canal sched mort : max(sched_last) sur tous les enregistrements du registre est obsolète au-delà de CHANNEL_DEAD_NANOS alors que /proc n'est pas vide. La garde /proc non vide est la garantie de vivacité : sur tout système Linux en fonctionnement, /proc n'est pas vide (init, threads noyau, kworkers), et l'ordonnanceur n'est jamais vraiment inactif (ticks d'horloge, I/O en attente, callbacks RCU). Un max(sched_last) obsolète sur un système non vide signifie que le canal est mort — pas que le système est inactif.

  2. Canal NMI mort : Aucun événement de battement de cœur (event_type=0) n'est arrivé du tampon circulaire NMI depuis plus de 5 secondes. Cela signifie que l'événement perf NMI a cessé de se déclencher — soit l'événement perf a été détaché, soit le PMU a été reprogrammé.

Les deux vérifications ont un temps de recharge de 30 secondes pour éviter une saturation d'alertes.

Détection de rootkit LD_PRELOAD ([HOOK])

SPiCa lit /proc via deux mécanismes indépendants à chaque tick :

  1. Appel système brut getdents64 (read_tgids()) — le std::fs::read_dir de Rust appelle cela directement via libc::syscall(SYS_getdents64, ...), contournant tous les hooks de fonctions libc. Les rootkits LD_PRELOAD ne peuvent pas intercepter ce chemin.

  2. libc readdir (read_tgids_libc()) — appelle libc::opendir / libc::readdir via FFI, ce qui passe par l'éditeur de liens dynamique et est totalement interceptable par les hooks de /etc/ld.so.preload.

Si getdents64 voit des PIDs que libc readdir ne voit pas, un rootkit en espace utilisateur accroche readdir pour cacher des processus. SPiCa déclenche [HOOK] :``` [HOOK] 3 PID(s) hidden from libc readdir — LD_PRELOAD rootkit suspected

root@kitploit:~
Cette technique transforme le privilège au niveau noyau de SPiCa en une détection active des rootkits en espace utilisateur. Le chemin d'appel système brut est la vérité de référence — aucun hook en espace utilisateur ne peut l'aveugler. Le chemin libc est la vue « perçue » qu'un outil normal (ps, ls) verrait. L'écart est une preuve sans ambiguïté d'interception de bibliothèque.

**Rootkits détectés par `[HOOK]` :**

| Rootkit | Mécanisme de dissimulation | Détecté |
|---------|-----------------|----------|
| Symbiote | LD_PRELOAD parasitaire, hook `readdir` | Oui (lorsqu'il se cache activement) |
| JynxKit | LD_PRELOAD, dissimulation par `MAGIC_GID` via `readdir` | Oui |
| Azazel | LD_PRELOAD, hooks `readdir` + `stat` | Oui |
| Medusa/OrBit | LD_PRELOAD, `readdir` + vol d'identifiants | Oui |

**Testé avec un vrai Symbiote :** Un échantillon réel de Symbiote (SHA256 `f55af21f...`, MalwareBazaar) a été déployé via `/etc/ld.so.preload` sur une VM Ubuntu 24.04. L'échantillon hooke `readdir`, `readdir64`, `stat`, `fstatat`, `pam_authenticate`, `pcap_loop`, `recvmsg`, `fopen`, `read`, `execve`. Lorsque le hook LD_PRELOAD cache activement un PID de `readdir`, SPiCa déclenche `[HOOK]` en un cycle de tick (<1 s). Lorsque Symbiote est chargé mais passif (ne se cache pas activement), SPiCa ne produit aucun faux positif.

### Fenêtre de grâce

Une fenêtre de grâce de 50 ms empêche les faux positifs sur les processus fraîchement créés (fork). Les vérifications SILENT au niveau du canal ont une période de grâce de 5 secondes (la référence `NMI_FIRST_TICK` du programme NMI) afin que la latence de démarrage ne produise pas de fausses alertes TAMPER.

---

## 6. Secret d'adresse borné par le vérificateur

### Définition

**Le secret d'adresse borné par le vérificateur** est une propriété de sécurité computationnelle qui tient dans le modèle d'adversaire contraint par eBPF. Il énonce :

> Étant donné un adversaire qui peut charger des programmes eBPF (CAP\_BPF) mais est contraint par le vérificateur BPF (boucles bornées, helpers restreints, pas d'écriture noyau arbitraire), l'adresse noyau de la section de données `.bss` d'un programme BPF est informatiquement infaisable à découvrir.

### Les quatre mécanismes

La propriété est une composition de quatre barrières indépendantes :

1. **kASLR** — La randomisation du layout de l'espace d'adressage noyau (KASLR) randomise la région du tas noyau où la mémoire des maps BPF (y compris les maps de support `.bss`) est allouée. L'adresse exacte change à chaque démarrage.

2. **Limite d'instructions du vérificateur** — Le vérificateur BPF limite le nombre total d'instructions par programme à environ 1 million et exige des boucles qui se terminent de manière prouvable. Un programme de scan d'un adversaire peut sonder au plus N ≈ 10^6 adresses par chargement via `bpf_probe_read_kernel`. Étant donné un espace de recherche randomisé par kASLR, la probabilité de succès par programme est négligeable.

3. **Passerelle d'accès aux maps LSM** (voir [§7](#7-lsm-map-access-gate)) — Sans la passerelle, un adversaire pourrait énumérer les maps BPF par ID (`BPF_MAP_GET_NEXT_ID` → `BPF_MAP_GET_FD_BY_ID` → `BPF_MAP_LOOKUP_ELEM`) et lire directement le contenu de `.bss`. La passerelle supprime ce chemin facile, forçant l'adversaire à emprunter le chemin de scan mémoire borné par le vérificateur.

4. **Placement de `.bss`** — Les variables globales `.bss` n'apparaissent pas dans les interfaces d'énumération de maps nommées avec des noms lisibles. La map de support interne `.bss` est nommée `.bss` par libbpf/aya, mais son contenu (les variables globales réelles) n'est accessible que si vous possédez le descripteur de fichier (fd) de la map. Le fd de la map nécessite soit la table des descripteurs du processus chargeur, soit l'ID de la map (bloqué par la passerelle).

### Structure de l'argument formel```
Adversary's goal:    locate SPiCa's .bss in kernel virtual memory
Search space:        kernel heap region, kASLR-randomized (~2^30 entropy)

Path A — map enumeration (blocked):
  BPF_MAP_GET_NEXT_ID → BPF_MAP_GET_FD_BY_ID → BPF_MAP_LOOKUP_ELEM
  → blocked by LSM gate (§7) for non-SPiCa processes

Path B — memory scan (bounded):
  bpf_probe_read_kernel(addr, buf, len) — fault-safe, accepts any addr
  Per-program capacity: N ≈ 10^6 probes (instruction limit)
  Success probability per load: N / |search space| ≈ 10^6 / 2^30 ≈ 10^-24
  Can reload programs, but: each load is a syscall (observable), and
  the target address doesn't change between loads (same boot session)

Path C — timing side channel (theoretical):
  bpf_probe_read_kernel timing varies on fault vs success
  Binary search over the heap could reduce scan complexity to O(log |A|)
  → O(30) probes, well within instruction budget
  LIMITATION: must be acknowledged. Mitigated by rate-limiting BPF_PROG_LOAD
  via the LSM gate (future work).

Ce qui rend ceci novateur

La plupart des recherches en sécurité BPF traitent le vérificateur comme une surface d'attaque (bugs du vérificateur, non-rigueur, spray JIT). Ce travail inverse le cadre : les contraintes du vérificateur sont une primitive défensive qui limite l'espace de recherche de l'adversaire. Le secret n'est pas cryptographique (ce n'est pas AES) ; il est calculatoire — limité par ce que le vérificateur permet à l'adversaire de calculer.

Limites (doivent être énoncées honnêtement)

  • Exploits du vérificateur — Si le vérificateur n'est pas rigoureux, la limite d'instructions est rompue et l'adversaire peut effectuer des calculs arbitraires. Cela sort du modèle de menace eBPF.
  • Canaux auxiliaires temporels — bpf_probe_read_kernel est observable temporellement (échec vs succès prend des cycles différents). Une recherche binaire basée sur le timing sur le tas est théoriquement plus efficace qu'un balayage linéaire. La limite d'instructions restreint les sondes par programme, mais la recherche binaire pourrait réduire le nombre de sondes à O(log |A|) ≈ 30. C'est une limitation réelle. Atténuation : limiter le débit de BPF_PROG_LOAD via la porte LSM.
  • Root espace utilisateur — Un processus root dans l'espace utilisateur (non contraint par le vérificateur) peut énumérer les cartes par ID. La porte LSM bloque cela, mais seulement pour les processus non-SPiCa. Un processus qui compromet le propre PID de SPiCa a un accès complet.

7. Porte d'accès aux cartes LSM

Le problème

Les globales .bss sont sauvegardées par une carte BPF interne. Tout processus avec CAP_BPF peut énumérer toutes les cartes sur le système :``` bpf(BPF_MAP_GET_NEXT_ID, …) → iterate all map IDs bpf(BPF_MAP_GET_FD_BY_ID, id) → get fd to any map bpf(BPF_MAP_LOOKUP_ELEM, fd, key, value) → read map contents

root@kitploit:~
Contre l'adversaire eBPF (qui ne peut pas appeler d'appels système), `.bss` est caché. Contre root en espace utilisateur, c'est une carte standard — entièrement lisible. La porte LSM comble cette lacune.

### La défense```
hook = "bpf"
  read cmd (arg 0)
  if cmd == BPF_MAP_GET_FD_BY_ID:
    read map_id from userspace bpf_attr (bpf_probe_read_user)
    if map_id matches any of SPiCa's stored IDs (.bss):
      if caller_tgid != SPICA_PID:
        return -EPERM

Map IDs sont écrites dans .bss par le chargeur espace utilisateur juste après le chargement du programme, avant que le hook LSM ne soit armé (même motif temporel que le sc_gate existant pour le blocage LKM). Pas besoin de BTF — cmd et map_id proviennent des arguments des appels système, pas des structures du noyau.

Chirurgical : ne bloque que l'accès aux map IDs spécifiques de SPiCa. Les outils BPF des autres processus (tcpdump, bpftrace, bcc) accèdent à leurs propres maps et ne sont pas affectés.

Ce qu'il ne couvre pas

  • ptrace / /proc/pid/mem — Un autre processus root pourrait lire directement la mémoire du processus SPiCa via ptrace, contournant entièrement l'appel système BPF. C'est une limitation fondamentale : on ne peut pas se protéger contre un processus ayant le même niveau de privilège lisant votre mémoire via /proc/pid/mem. Défense : envoi des logs hors hôte (si l'attaquant peut lire la mémoire locale, il peut aussi supprimer les alertes locales — seule la journalisation à distance aide).
  • PID propre de SPiCa compromis — Si l'attaquant prend le contrôle du processus SPiCa, il a un accès légitime aux maps.

8. Gestion des clés et obfuscation

Clé provenant du TPM

Sur les hôtes équipés d'un TPM, la clé d'obfuscation XOR 64 bits est obtenue via TPM2_GetRandom via la crate tss-esapi (appel direct à la bibliothèque libtss2-esys). La clé ne transite par aucun tube, aucune ligne de commande de sous-processus, aucun disque. Elle n'existe que dans le matériel TPM et dans la mémoire volatile du noyau (map de support .bss) pendant la durée du processus SPiCa.

Sur les hôtes sans TPM (VM sans vTPM, conteneurs, machines sans puce TPM), SPiCa utilise une clé de compilation par build générée à partir de /dev/urandom par le script de construction. Le recul est visiblement bruyant au démarrage avec une bannière d'avertissement.

Placement dans .bss

Les valeurs suivantes se trouvent dans la section .bss du programme eBPF, écrites par l'espace utilisateur via set_global() avant le chargement de tout programme :

Les maps BPF nommées sont énumérables via l'interface d'itération de maps de l'appel système bpf() (bloquée par la porte LSM — voir §7); les globales .bss sont accessibles via la même map interne mais ne sont ni nommées séparément ni épinglables.

Obfuscation XOR — défense contre les fuites de lecture, pas du chiffrement

Tous les champs de ProcessInfo sont repliés XOR avec la BASE_KEY 64 bits avant d'être écrits dans les tampons circulaires. Le champ event_type est intentionnellement laissé non obfusqué pour que l'espace utilisateur puisse le lire comme sentinelle avant de désobfusquer le reste.

Il s'agit d'obfuscation contre les fuites de lecture, pas de chiffrement contre un adversaire capable. XOR avec une clé répétitive de 8 octets est structurellement vulnérable au texte clair connu : des valeurs comm prévisibles ("bash", "systemd", "kthreadd") XORées contre le texte chiffré récupèrent directement les octets de la clé. La défense est appropriée pour l'adversaire eBPF (qui ne peut pas facilement lire le tampon circulaire — cela nécessite le même écart de capacité qui protège .bss), pas pour un adversaire ayant un accès binaire + interception du tampon circulaire.


9. Scellement TPM lié aux PCR (Conception)

Statut : Phase de conception. Pas encore implémenté. Cette section documente l'architecture cible pour l'article de recherche.

Aperçu

Le scellement TPM lié aux PCR déplace la frontière de distribution de clés de la couche logicielle vers le silicium. La clé est scellée à l'installation contre les valeurs attendues des registres de configuration de plateforme (PCR), et ne peut être déscellée que si l'état de démarrage du système correspond aux mesures attendues.

Chaîne de mesure de démarrage

Pendant le démarrage, le firmware, le chargeur d'amorçage et le noyau mesurent des composants critiques dans les PCR :

Remarque : L'allocation des PCR dépend de la chaîne de démarrage. GRUB mesure le noyau dans PCR 4 ; systemd-stub mesure dans PCR 4 et la ligne de commande dans PCR 8. La politique de scellement doit correspondre à la chaîne de démarrage cible.

Le flux sceller → désceller → injecter → échec sécurisé

  1. Sceller (à l'installation) : La clé 64 bits est scellée contre les valeurs PCR attendues en utilisant TPM2_Create avec une session TPM2_PolicyPCR. Le blob scellé est stocké sur disque. Il est chiffré avec la clé interne du TPM et ne peut être déchiffré que lorsque les PCR spécifiées correspondent.
  2. Désceller (démarrage précoce, étape initramfs) : Avant que tout code espace utilisateur non fiable ne s'exécute, le hook initramfs de SPiCa demande TPM2_Unseal. Si les valeurs PCR actuelles correspondent à la politique de scellement, le TPM libère la clé.
  3. Injecter : La clé est écrite dans .bss via set_global() avant le chargement des programmes.
  4. Le piège : Si un attaquant a modifié le noyau (PCR 4 non correspondant), échangé l'initramfs (PCR 9 non correspondant), ou altéré la politique Secure Boot (PCR 7 non correspondant), les hachages PCR divergent. Le TPM refuse de désceller, et SPiCa échoue de manière sécurisée — il refuse de démarrer plutôt que de tourner à l'aveugle avec une clé compromise.

Options de politique PCR

Pour l'article de recherche, présentez la politique forte et discutez du compromis du re-scellement dans les limitations.

Relation avec le secret d'adresse limité par le vérifieur

Les deux mécanismes sont complémentaires :

  • Le scellement PCR protège la clé au démarrage — il garantit que la clé n'est disponible que dans un état système de confiance.
  • Le secret d'adresse limité par le vérifieur + la porte LSM protègent la clé à l'exécution — ils garantissent que l'adversaire eBPF ne peut pas localiser ou lire le .bss où se trouve la clé.

Aucun des deux n'est suffisant seul. Le scellement PCR n'aide pas si la clé est compromise à l'exécution (énumération des maps). Le secret d'adresse n'aide pas si le système a été compromis avant le démarrage de SPiCa (initramfs hostile).

Ce que le scellement PCR ne détecte PAS

  • Détachement à l'exécution des programmes LSM — Les programmes LSM BPF (spica_lsm_modblock, la porte d'accès aux maps) sont chargés à l'exécution et NE sont PAS mesurés dans un PCR. Un rootkit qui les détache après le démarrage n'est pas détecté par le scellement PCR. Ce qui le détecte, c'est le heartbeat NMI (détectant que le système de détection lui-même a cessé de fonctionner).
  • Exploitation du noyau après démarrage — Si le noyau est exploité après le démarrage (corruption mémoire → écriture arbitraire), les PCR sont inchangés. C'est l'objectif non atteint de « nation-state ».

10. Défense en profondeur

SPiCa est la dernière couche de contrôle. Il complète un système correctement configuré, il ne remplace pas les couches supérieures.```mermaid flowchart TD SB["UEFI Secure Boot
─────────────────────────────
Verifies bootloader signature against
the UEFI db certificate store
Measured to PCR 7"] MS["Kernel Module Signing
─────────────────────────────
CONFIG_MODULE_SIG_FORCE=y
Kernel rejects unsigned .ko at load time"] IMA["IMA, Integrity Measurement Architecture
─────────────────────────────
Measures file hashes to TPM PCR10
Appraise policy blocks non-matching signatures"] SPICA["SPiCa
─────────────────────────────
LSM gate: blocks LKM loads + map enumeration
sched_switch + NMI integrity channels
Differential detection: DKOM · GHOST · TAMPER · SILENT · DUPE
PCR-bound key sealing (design phase)"]

root@kitploit:~
SB  -->|"boot chain verified"| MS
MS  -->|"signed modules only"| IMA
IMA -->|"measured + appraised"| SPICA

classDef firmware fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#78350f
classDef kernel   fill:#fdf2f8,stroke:#9333ea,stroke-width:2px,color:#581c87
classDef spica    fill:#eff6ff,stroke:#2563eb,stroke-width:2px,color:#1e3a8a
class SB firmware
class MS,IMA kernel
class SPICA spica
root@kitploit:~
SPiCa vérifie les quatre couches au démarrage et affiche leur statut.

---

## 11. L'incident du bug BTF

### Ce qui s'est passé

Lors des tests sur Ubuntu (noyau le plus récent), une incompatibilité BTF a fait que le programme du tracepoint `sched_switch` s'est attaché avec succès mais **n'a jamais déclenché un seul événement.** L'appel système `attach()` a retourné `Ok(())`, donc SPiCa a continué normalement — mais le tampon circulaire sched est resté vide. Aucune alerte de détection ne s'est déclenchée car le moteur de détection n'avait pas de données de planification. **SPiCa a fonctionné à l'aveugle sans aucune indication d'échec.**

C'est le mode d'échec le plus grave pour un outil de sécurité : la cécité silencieuse.

### Pourquoi cela n'a pas été détecté

Le moteur de détection original raisonnait **par processus** : chaque enregistrement de processus avait les horodatages `sched_last` et `nmi_last`, et la vivacité était calculée par enregistrement. Lorsque sched\_switch est mort globalement :

1. `sched_live` est passé à faux pour chaque enregistrement (pas de nouveaux événements sched → toutes les valeurs `sched_last` vieillissent)
2. Le prédicat `TAMPER` par processus (`in_proc && nmi_live && !sched_live`) pouvait se déclencher, mais nécessitait que `nmi_live` soit maintenu *en continu* pendant 2 secondes. Les échantillons NMI sont rares (période de 10M cycles), donc `suspect_since` se réinitialisait constamment à cause de la gigue d'échantillonnage et n'arrivait jamais à maturité.
3. Le prédicat `SILENT` par processus nécessitait `sched_live`, qui était maintenant faux pour tout — le prédicat s'inversait exactement dans la condition qu'il était censé détecter.
4. Il n'y avait **aucune vérification de vivacité au niveau du canal** — aucun mécanisme du type "est-ce que sched a JAMAIS été déclenché ?" ou "est-ce que max(sched_last) est obsolète ?".

De plus, une inadéquation de base de temps a été découverte : `sched_last` stockait `bpf_ktime_get_ns()` (nanosecondes de démarrage du noyau) tandis que `evaluate()` comparait avec `nanos_since_startup()` (nanosecondes locales du processus). Le `wrapping_sub` de ces bases de temps différentes produisait des valeurs énormes, rendant tous les prédicats de vivacité trivialement faux. La logique de détection n'avait jamais fonctionné correctement en production — le bug BTF l'a simplement masqué en empêchant les événements d'arriver du tout.

### Comment la refonte le corrige

| Problème | Correction |
|---|---|
| Aucune vérification de vivacité au niveau du canal | `evaluate()` calcule maintenant `max(sched_last)` et déclenche `[SILENT]` si obsolète alors que `/proc` n'est pas vide |
| TAMPER par processus n'arrivait jamais à maturité (réinitialisation par gigue) | TAMPER est maintenant un signal direct du programme NMI (comparaison du battement de cœur `.bss`), pas un FSM par processus avec des seuils |
| SILENT par processus s'inversait quand sched mourait | SILENT est maintenant au niveau du canal, calculé à partir d'agrégats, pas des prédicats par enregistrement |
| Inadéquation de base de temps | `sched_last` stocke maintenant le temps local du processus (paramètre `now`), pas `bpf_ktime_get_ns()` |
| NMI était une observation redondante | NMI est maintenant un vérificateur d'intégrité — il détecte la mort de sched directement via le battement de cœur `.bss` |

---

## 12. Limitations connues et surface d'attaque

### Dans le modèle de menace eBPF

| Attaque | Statut | Notes |
|---|---|---|
| **Manipulation du pointeur consommateur du tampon circulaire** | **Détecté** (SILENT) | `max(sched_last)` devient obsolète → SILENT. `SCHED_HEARTBEAT` continue d'avancer (le programme s'exécute) → pas de faux TAMPER. |
| **DKOM de la structure d'événement Perf** (champ `state` mis à zéro) | **Détecté** (SILENT) | NMI cesse de se déclencher → pas d'événements de battement de cœur → SILENT sur le canal NMI |
| **Usurpation de champ `task_struct`** (écraser pid/tgid) | **Partiel** (DUPE) | Si le TGID usurpé correspond à un enregistrement existant avec un `start_time_ns` différent, DUPE se déclenche. Si `start_time_ns` est également usurpé, cela passe inaperçu. |
| **Détachement du programme eBPF** (suppression du tableau funcs) | **Détecté** (TAMPER) | Le battement de cœur NMI se fige → TAMPER |
| **Correctif du bytecode sur place** | **Non détecté** | Nécessite une écriture arbitraire dans le noyau (niveau LKM) — en dehors du modèle de menace eBPF |
| **Canal auxiliaire temporel sur `bpf_probe_read_kernel`** | **Risque théorique** | Une recherche binaire sur le tas pourrait trouver `.bss` en ~30 sondes. Voir les limitations [§6](#6-verifier-bounded-address-secrecy). |

### En dehors du modèle de menace eBPF (reconnu, non résolu)

| Attaque | Statut | Notes |
|---|---|---|
| **Hameçonnage du gestionnaire IDT/NMI** | **La bombe vivante** | Contournement architectural complet. Panique noyau quasi certaine. |
| **Suppression double canal** | **La bombe vivante** | Supprimer simultanément sched + NMI. Hérite de l'instabilité du hameçonnage NMI. |
| **Exploitation du vérificateur** | **Non-objectif** | Échappe à l'exécution de code noyau arbitraire. Classe de menace distincte. |
| **ptrace / `/proc/pid/mem`** | **Limitation fondamentale** | Lecture mémoire de même privilège. Seul l'envoi de logs hors hôte aide. |
| **Pointeur consommateur + correctif du battement de cœur** | **Niveau LKM** | Si l'attaquant a une écriture arbitraire dans le noyau, il peut à la fois avancer le pointeur consommateur ET écrire de faux battements de cœur. Mais écriture arbitraire dans le noyau = niveau LKM = en dehors du modèle de menace. |

---

## 13. Construction et exécution

### Prérequis

- Linux kernel >= 5.15 avec `CONFIG_DEBUG_INFO_BTF=y` (uniquement pour le crochet LSM)
- Pour le blocage de modules : `CONFIG_BPF_LSM=y` et `lsm=bpf` dans la ligne de commande du noyau
- Puce TPM 2.0 + bibliothèque `tpm2-tss` (optionnel ; se replie avec un avertissement visible)
- Chaîne d'outils Rust nightly

> **Note :** L'étape `generate-vmlinux` n'est **plus requise**. Les programmes eBPF utilisent des décalages de tracepoint traditionnels et des globales `.bss` — aucune navigation de structure CO-RE/BTF n'est nécessaire. La commande xtask `generate-vmlinux` est conservée pour une utilisation future mais ne fait pas partie du pipeline de construction.

Vérifiez que BPF LSM est actif : `cat /sys/kernel/security/lsm` doit contenir `bpf`.

### Configuration```shell
make install-deps     # system packages + nightly Rust (pacman/apt/dnf auto-detected)
make install-tools    # bpf-linker
make build            # compiles eBPF + userspace (no vmlinux generation needed)

Exécution```shell

make run # sudo ./target/release/spica

root@kitploit:~
### Installation dans initramfs (protection au démarrage précoce)```shell
sudo make install     # spica install — auto-detects Debian (initramfs-tools) or Fedora (dracut)

Vérifiez que cela fonctionne```shell

sudo insmod some_module.ko # should fail with EPERM (gate locked) cat /sys/kernel/security/lsm # should contain 'bpf' ls /sys/fs/bpf/spica_watchdog # exists if previous run was killed ungracefully

root@kitploit:~
### Développement (macOS ou Linux)

Les programmes eBPF ne peuvent pas s'exécuter sous macOS. `cargo check` et les tests unitaires pour la logique de détection fonctionnent ; la vérification complète en environnement d'exécution nécessite Linux.```shell
make check      # cargo check for workspace
make check-ebpf # cargo check for the eBPF crate (bpfel-unknown-none)
make test       # unit tests for detection FSM, key derivation, obfuscation

14. Feuille de route

  • Scellement de clé lié aux PCR — attestation matérielle réelle. Lors de l'installation, sceller la clé aux valeurs PCR attendues (PCR 4/7/9/10). À l'exécution, le déscellement échoue si les PCR ont changé. Remplace l'utilisation TPM actuelle basée uniquement sur GetRandom par une racine de confiance matérielle complète. Voir §9.
  • Porte d'accès aux maps LSM — hook BPF LSM sur l'appel système bpf bloquant l'énumération des maps de l'état interne de SPiCa depuis des processus non SPiCa. Voir §7.
  • Limitation de débit de BPF_PROG_LOAD — Étendre la porte LSM pour limiter le débit des chargements de programmes BPF depuis des processus non SPiCa, atténuant le risque de canal latéral temporel sur la découverte de .bss. Voir les limitations du §6.
  • Mise à niveau de l'obscurcissement PRF SipHash — Si le modèle de menace inclut des adversaires ayant un accès en lecture au ring buffer, remplacer XOR par un flux de clé SipHash-1-3 (la dépendance siphasher est déjà dans l'arbre pour le jeton d'intégrité).
  • Backend de journalisation entreprise — Livraison optionnelle vers Elasticsearch/Elastic SIEM pour les environnements SOC. Toutes les alertes, événements de terminaison et anomalies du compteur de redémarrage sont envoyés hors de l'hôte en temps réel.
  • Prise en charge de distributions supplémentaires — Arch (mkinitcpio), openSUSE.
  • Pipeline CI — Tests de fumée Linux exerçant le flux réel de chargement + attachement eBPF + ring buffer.

15. Glossaire


Licence

Licence SPiCa Engine : MIT OU Apache-2.0 (workspace). Le programme eBPF exporte une licence GPL via la statique _license — il s'agit d'une exigence du noyau pour les programmes eBPF utilisant des helpers sous licence GPL, et s'applique uniquement au bytecode eBPF chargé, pas au binaire espace utilisateur.

Attribution du personnage : "Hatsune Miku" et les œuvres artistiques associées sont des propriétés protégées par le droit d'auteur de Crypton Future Media, INC. (www.piapro.net). Ce projet est un outil de recherche indépendant et non commercial, non affilié à Crypton Future Media. Personnage utilisé sous la Piapro Character License (PCL).

Le nom du projet SPiCa est inspiré de la chanson originale de Toku-P.

Télécharger l’outil
ContrainteEffet sur l'adversaire
Boucles bornées (~1M instructions par programme)Ne peut pas scanner toute la mémoire du noyau
Sécurité des pointeurs (le déréférencement direct nécessite une cible prouvablement valide et bornée)Ne peut pas suivre des pointeurs arbitraires
Aides restreintes (liste blanche par type de programme)Ne peut pas appeler kmalloc, vmalloc ni aucune fonction d'allocation du noyau
Aucune écriture arbitraire dans le noyau (bpf_probe_write_kernel fortement restreint)Ne peut pas modifier task_struct, les tableaux de fonctions de tracepoint, ni le bytecode du programme BPF
Accès aux cartes limité aux références chargéesNe peut pas accéder aux cartes appartenant à d'autres programmes (sauf énumération par ID — voir §7)
CanalMécanismeCe qui le supprimeCoût de la suppression
/procÉnumération de répertoire procfsDKOM (détacher le processus de la liste des tâches)Faible — technique de rootkit bien connue
sched_switchTracepoint eBPF sur l'ordonnanceurDétacher le programme du tableau funcs ; filtrer le contexteMoyen — nécessite une écriture noyau dans le tableau funcs
NMIInterruption du compteur de performance matériel → événement de performance eBPFAccrocher le gestionnaire IDT/NMIPanique du noyau presque certaine — interruption matérielle, non masquable
AlerteConditionCe qu'il détecte
[DKOM]TGID programmé par le noyau absent de /proc pendant >2 sManipulation directe d'objets du noyau — processus caché de l'énumération en espace utilisateur
[GHOST]TGID présent dans /proc mais jamais vu par sched_switch pendant >5 sSpoofing de /proc — entrée factice insérée pour contourner les vérifications DKOM
[TAMPER]NMI détecte un battement de cœur sched_switch gelé (event_type=1)Point de trace détaché, supprimé, ou échec BTF/attach
[SILENT]max(sched_last) obsolète sur tout le registre alors que /proc est non vide ; ou battement de cœur NMI absent pendant >5 sPerte d'observation au niveau du canal — le canal sched ou NMI est mort
[DUPE]Même TGID, start_time_ns différent entre événementsSpoofing de champ task_struct — le rootkit modifie tgid pour usurper un processus légitime
[HOOK]PIDs visibles via getdents64 brut mais absents du readdir de libcRootkit LD_PRELOAD — interception de bibliothèque utilisateur cachant des processus à ps, ls et autres outils (Symbiote, JynxKit, Azazel, Medusa/OrBit)
[WATCHDOG]Le pin /sys/fs/bpf/spica_watchdog existe au démarrageInstance précédente tuée non proprement (SIGKILL, OOM, crash)
[LKM-ALLOW]READING_MODULE intercepté alors que la porte est ouverte (fenêtre de démarrage)Enregistrement d'audit : module chargé avant le verrouillage de la porte
[LKM-DENY]READING_MODULE intercepté alors que la porte est verrouilléeinsmod/modprobe bloqué après l'initialisation
GlobalObjectifÉcrit par
BASE_KEYClé d'obfuscation XORespace utilisateur au chargement
SPICA_PIDTGID propre de SPiCa (watchdog)espace utilisateur au chargement
SCHED_HEARTBEATHorodatage de vivacité sched_switchprogramme sched_switch à chaque invocation
NMI_LAST_HBEnregistrement NMI du dernier heartbeat schedprogramme NMI à chaque vérification
NMI_FIRST_TICKPremière invocation ktime NMI (période de grâce)programme NMI à la première invocation
NMI_LAST_EMITLimitation : dernière émission ktimeprogramme NMI à chaque émission
PCRCe qui est mesuréStabilité
PCR 4Code du chargeur d'amorçage + image du noyau (GRUB mesure les deux)Change lors d'une mise à jour du noyau
PCR 5Table de partitions GPT/MBR, configuration de démarrageStable entre les mises à jour
PCR 7Politique Secure Boot (politique SI, MOK, db/dbx)Stable entre les mises à jour du noyau
PCR 8Ligne de commande du noyau (mesures systemd-stub)Stable sauf si la ligne de commande change
PCR 9Initramfs (GRUB mesure initrd ici)Change lors d'une mise à jour d'initramfs
PCR 10Liste de mesures IMAChange à mesure que les exécutables sont mesurés
PolitiqueScellé contreRobustesseCoût opérationnel
FortePCR 4 + 7 + 9 + 10Détecte les modifications du noyau, de l'initramfs, du Secure Boot et de l'IMARe-sceller après chaque mise à jour du noyau/initramfs
ÉquilibréePCR 7 + 10Détecte les modifications du Secure Boot et de l'évaluation IMA ; stable entre les mises à jour du noyauRe-sceller uniquement lors d'un changement de politique Secure Boot ou de politique IMA
MinimalePCR 7 uniquementDétecte uniquement les changements d'état du Secure BootTrès stable ; liaison la plus faible
TermeDéfinition
BPFBerkeley Packet Filter — moteur d'exécution noyau pour programmes sandboxés. Le BPF moderne (eBPF) s'étend au-delà des paquets vers le traçage, la sécurité et le réseau.
BTFBPF Type Format — informations de débogage du noyau qui permettent aux programmes CO-RE (Compile Once, Run Everywhere) de naviguer dans les structures du noyau de manière portable.
CO-RECompile Once, Run Everywhere — technique BPF utilisant BTF pour écrire des programmes portables qui s'adaptent à différentes versions du noyau.
DKOMDirect Kernel Object Manipulation — technique de rootkit consistant à supprimer un processus de la liste chaînée du noyau pour le cacher de /proc.
fmod_retType de programme BPF qui modifie la valeur de retour d'une fonction du noyau via le trampoline BPF.
freplaceExtension de programme BPF — se fixe à une (sous-)fonction spécifique d'un autre programme BPF, interceptant son exécution.
tableau funcsTableau de pointeurs de fonction dans une structure de point de trace du noyau qui contient les fonctions de rappel (y compris les programmes BPF) à invoquer lorsque le point de trace se déclenche.
IDTInterrupt Descriptor Table — structure CPU qui associe les vecteurs d'interruption aux fonctions de gestion. Le hookage de l'entrée NMI nécessite le patching de l'IDT.
kASLRKernel Address Space Layout Randomization — randomise les adresses du code/données du noyau à chaque démarrage pour entraver l'exploitation.
NMINon-Maskable Interrupt — interruption matérielle qui ne peut pas être désactivée par logiciel (cli). Utilisée par les compteurs perf pour l'observation au niveau matériel.
PCRPlatform Configuration Register — registre TPM qui accumule les mesures (hachages) des composants de démarrage. Ne peut pas être réinitialisé (sauf redémarrage), seulement étendu.
PMUPerformance Monitoring Unit — compteurs matériels dans le CPU qui comptent les événements (cycles, échecs de cache, etc.) et peuvent déclencher des interruptions (NMI) à des seuils.
TPMTrusted Platform Module — coprocesseur cryptographique fournissant un stockage de clés basé sur le matériel, une génération de nombres aléatoires et une attestation de mesures.
VérifieurLe vérifieur BPF — composant du noyau qui analyse statiquement les programmes BPF avant leur chargement pour garantir qu'ils se terminent et n'accèdent pas à de la mémoire non sécurisée.