
SunnyDayBPF : recherche sur le leurrage de télémétrie des tampons utilisateur post-syscall basée sur eBPF par Azizcan Daştan
SunnyDayBPF est une technique de recherche sur la tromperie de télémétrie de tampon utilisateur post-syscall basée sur eBPF, initialement proposée et étudiée par Azizcan Dastan.
Cette technique étudie si les données observées par les agents de sécurité, de journalisation ou de télémétrie en espace utilisateur peuvent être altérées après qu'un syscall de type lecture s'est terminé, mais avant que l'agent ne parse, n'analyse ou ne transmette ces données à un pipeline de sécurité en aval.
L'idée centrale est la suivante :
L'événement a toujours lieu.
L'agent de surveillance lit toujours les données.
Mais les données observées par l'agent peuvent ne plus représenter entièrement l'événement d'origine.
SunnyDayBPF se concentre sur l'écart entre la vérité terrain et la télémétrie observée.
SunnyDayBPF Hook Points
========================
Telemetry Agent Process +---------------------------------------------------------+ | | | read() pread64() recvfrom() | | | | | | +-----|----------------|------------------|---------------+ | | | ======|================|==================|======= KERNEL BOUNDARY | | | kprobe:ksys_read kprobe:_x64_sys kprobe:_sys (save buf ptr) pread64 recvfrom | (nested pt_regs) (save buf ptr) | (save buf ptr) | v v v [syscall executes — data enters user buffer] | | | kretprobe kretprobe kretprobe | | | +--------+-------+---------+--------+ | | read buffer into initialize BPF scratch space scan_state | v +------------------+ | TAIL CALL CHAIN | | | | scan_g0: SECURITY (4 rules, scan=177 bytes) | scan_g1: SECURITY (4 rules, scan=173 bytes) | scan_g2: SEVERITY (4 rules, scan=177 bytes) | scan_g3: SEVERITY (1 rule, scan=251 bytes) | scan_g4: PATH (4 rules, scan=132 bytes) | scan_g5: AUTH (4 rules, scan=190 bytes) | scan_g6: AUTH (1 rule, scan=249 bytes) | scan_g7: NETWORK (3 rules, scan=249 bytes) | scan_g8: PROCESS (4 rules, scan=173 bytes) | scan_g9: CUSTOM (2 rules, scan=243 bytes) | | | emit_event: | | perf event | | + stats | +------------------+ | v bpf_probe_write_user() (modify agent's buffer) | v read-back verification (confirm write succeeded) | v Agent continues with modified data
### Couverture des syscalls
| Syscall | Hook noyau | Extraction d'arguments | Couverture |
|---------|------------|----------------|----------|
| `read()` | `ksys_read` | `PT_REGS_PARM2` (direct) | Lectures de fichiers, pipes, `/proc`, fichiers de log |
| `pread64()` | `__x64_sys_pread64` | `pt_regs` imbriqués via `bpf_probe_read_kernel` (offset 104/RSI) | Lectures de fichiers à accès aléatoire, journald |
| `recvfrom()` | `__sys_recvfrom` | `PT_REGS_PARM2` (direct) | Sockets réseau, transfert syslog |
### Contraintes du vérificateur BPF
Le vérificateur BPF impose une limite de séquence de sauts de 8 192 branches conditionnelles par programme. SunnyDayBPF contourne cette limitation en utilisant :
- **Appels de queue BPF** (`BPF_PROG_ARRAY`) : 31 règles réparties sur 10 programmes indépendants, chacun avec son propre budget de vérificateur
- **Optimisation insensible à la casse** : `(d[i]|32)==lower` réduit les sauts par octet de 2 à 1 pour les caractères alphabétiques
- **Limites dynamiques de balayage** : La fenêtre de balayage de chaque groupe est calculée comme `min(BUF_SIZE - max_pat, 7800 / jumps_per_iter)` pour rester dans les limites du vérificateur
- **Tableaux par CPU** : `BPF_PERCPU_ARRAY` pour le tampon temporaire et l'état de balayage, partagés entre les programmes invoqués par tail calls
---
## Aperçu
Les systèmes de sécurité Linux modernes s'appuient souvent sur des agents en espace utilisateur qui collectent la télémétrie à partir de fichiers, de sockets, de pipes, d'API, d'interfaces noyau ou de flux d'événements.
Ces agents peuvent transmettre la télémétrie à :
- Plateformes SIEM
- Backends EDR/XDR
- Pipelines d'audit
- Collecteurs de journaux
- Moteurs de sécurité runtime
- Systèmes d'ingénierie de détection
- Plateformes d'observabilité
Une hypothèse courante est :```text
actual system behavior == collected telemetry == observed security data
SunnyDayBPF remet en question cette hypothèse.
La recherche explore un modèle de déception post-syscall où un processus de surveillance reçoit des données normalement, mais le tampon contenant ces données est modifié avant que le processus ne les consomme.```text actual system behavior != observed telemetry
---
## Définition technique
SunnyDayBPF est une technique de déception de télémétrie post-syscall qui étudie la manipulation des buffers d'espace utilisateur appartenant à des processus sélectionnés consommant de la télémétrie.
À un niveau élevé, la technique suit ce modèle :```text
sys_enter_*:
identify a target telemetry-consuming process
record the user-space buffer pointer involved in the read-like operation
sys_exit_*:
verify that the read-like operation completed successfully
inspect the returned user-space buffer
selectively alter telemetry-relevant content
verify write success via read-back
allow the target process to continue execution normally
Cela crée une inadéquation entre :```text what happened on the system
et:```text
what the monitoring agent later observes, parses, and forwards
SunnyDayBPF identifie les processus cibles par correspondance de préfixe de nom de commande de 5 caractères.
| Agent | Préfixe | Méthode de lecture | Efficace ? |
|---|---|---|---|
| Wazuh | wazuh | read() sur les fichiers journaux, syslog, journaux d'audit | Oui |
| OSSEC | ossec | read() sur les fichiers journaux | Oui |
| Splunk UF | splun | read() sur les fichiers surveillés | Oui |
| Elastic Agent | elast | read() sur les sources de journaux | Oui |
| Datadog Agent | datad | read() sur les journaux et les métriques | Oui |
| Cribl | cribl | read() pour le routage des journaux | Oui |
| Agent | Préfixe | Méthode de lecture | Efficace ? |
|---|---|---|---|
| rsyslog | rsysl | read() / recvfrom() sur syslog | Oui |
| syslog-ng | syslo | read() / recvfrom() sur syslog | Oui |
| Filebeat | fileb | read() sur les fichiers journaux | Oui |
| Fluent-bit | fluen | read() / recvfrom() sur les entrées | Oui |
| Fluentd | fluen | read() / recvfrom() sur les entrées | Oui |
| Logstash | logst | read() / recvfrom() sur le pipeline | Oui |
| Promtail | promt | read() sur les fichiers journaux (Loki) | Oui |
| Vector | vecto | read() sur les sources de journaux | Oui |