
SunnyDayBPF: Azizcan Daştan의 eBPF 기반 시스템 호출 후 사용자 버퍼 텔레메트리 기만 연구
SunnyDayBPF는 Azizcan Dastan에 의해 최초로 제안되고 연구된 eBPF 기반 post-syscall user-buffer telemetry deception 연구 기법입니다.
이 기법은 사용자 공간 보안, 로깅 또는 텔레메트리 에이전트에 의해 관찰된 데이터가 read-like syscall이 완료된 이후, 그러나 에이전트가 해당 데이터를 파싱, 분석 또는 다운스트림 보안 파이프라인으로 전달하기 전에 변경될 수 있는지 여부를 조사합니다.
핵심 개념은 다음과 같습니다:
이벤트는 여전히 발생합니다.
모니터링 에이전트는 여전히 데이터를 읽습니다.
하지만 에이전트가 관찰한 데이터는 더 이상 원본 이벤트를 완전히 대표하지 않을 수 있습니다.
SunnyDayBPF는 ground truth와 관찰된 텔레메트리 사이의 간극에 초점을 맞춥니다.
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
### 시스템 호출 커버리지
| 시스템 호출 | 커널 후크 | 인수 추출 | 커버리지 |
|---------|------------|----------------|----------|
| `read()` | `ksys_read` | `PT_REGS_PARM2` (직접) | 파일 읽기, 파이프, `/proc`, 로그 파일 |
| `pread64()` | `__x64_sys_pread64` | 중첩된 `pt_regs`를 `bpf_probe_read_kernel`을 통해 (오프셋 104/RSI) | 랜덤 액세스 파일 읽기, journald |
| `recvfrom()` | `__sys_recvfrom` | `PT_REGS_PARM2` (직접) | 네트워크 소켓, syslog 전달 |
### BPF 검증기 제약 조건
BPF 검증기는 프로그램당 최대 8,192개의 조건부 분기 시퀀스 제한을 적용합니다. SunnyDayBPF는 이를 다음과 같이 우회합니다:
- **BPF 테일 콜** (`BPF_PROG_ARRAY`): 31개의 규칙을 10개의 독립적인 프로그램에 분산, 각 프로그램은 자체 검증기 예산을 가짐
- **대소문자 구분 없는 최적화**: `(d[i]|32)==lower`는 알파벳 문자에 대해 바이트당 점프 수를 2에서 1로 줄임
- **동적 스캔 제한**: 각 그룹의 스캔 창은 `min(BUF_SIZE - max_pat, 7800 / jumps_per_iter)`로 계산되어 검증기 제한 내에 머물도록 함
- **CPU별 배열**: 스크래치 버퍼와 스캔 상태를 위한 `BPF_PERCPU_ARRAY`, 테일 콜된 프로그램 간에 공유됨
---
## 개요
현대 Linux 보안 시스템은 종종 파일, 소켓, 파이프, API, 커널 인터페이스 또는 이벤트 스트림에서 텔레메트리를 수집하는 사용자 공간 에이전트에 의존합니다.
이러한 에이전트는 텔레메트리를 다음으로 전달할 수 있습니다:
- SIEM 플랫폼
- EDR/XDR 백엔드
- 감사 파이프라인
- 로그 수집기
- 런타임 보안 엔진
- 탐지 엔지니어링 시스템
- 관측 가능성 플랫폼
일반적인 가정은 다음과 같습니다:```text
actual system behavior == collected telemetry == observed security data
SunnyDayBPF는 그 가정에 도전합니다. 이 연구는 모니터링 프로세스가 데이터를 정상적으로 수신하지만, 프로세스가 해당 데이터를 소비하기 전에 데이터를 포함한 버퍼가 수정되는 시스템 콜 후 기만 모델을 탐구합니다.```text actual system behavior != observed telemetry
## 기술적 정의
SunnyDayBPF는 시스템 호출 후(post-syscall) 텔레메트리 기만 기술로, 선택된 텔레메트리 소비 프로세스에 속한 사용자 공간 버퍼의 조작을 연구합니다.
높은 수준에서 이 기술은 다음 모델을 따릅니다:```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
이는 다음과 사이에 불일치를 발생시킵니다:```text what happened on the system
그리고:```text
what the monitoring agent later observes, parses, and forwards
SunnyDayBPF는 5자 명령어 이름 접두사 일치를 통해 대상 프로세스를 식별합니다.
| 에이전트 | 접두사 | 읽기 방식 | 유효함? |
|---|---|---|---|
| Wazuh | wazuh | read() on 로그 파일, syslog, 감사 로그 | 예 |
| OSSEC | ossec | read() on 로그 파일 | 예 |
| Splunk UF | splun | read() on 모니터링되는 파일 | 예 |
| Elastic Agent | elast | read() on 로그 소스 | 예 |
| Datadog Agent | datad | read() on 로그 및 메트릭 | 예 |
| Cribl | cribl | read() on 로그 라우팅 | 예 |
| 에이전트 | 접두사 | 읽기 방식 | 유효함? |
|---|---|---|---|
| rsyslog | rsysl | read() / recvfrom() on syslog | 예 |
| syslog-ng | syslo | read() / recvfrom() on syslog | 예 |
| Filebeat | fileb | read() on 로그 파일 | 예 |
| Fluent-bit | fluen | read() / recvfrom() on 입력 | 예 |
| Fluentd | fluen | read() / recvfrom() on 입력 | 예 |
| Logstash | logst | read() / recvfrom() on 파이프라인 | 예 |
| Promtail | promt | read() on 로그 파일 (Loki) | 예 |
| Vector | vecto | read() on 로그 소스 | 예 |
| 에이전트 | 접두사 | 읽기 방식 | 유효함? |
|---|---|---|---|
| Falco | falco | eBPF 이벤트가 perf 버퍼에서 read()를 통해 수집됨 | 예 |
| osquery | osque | /proc, 로그 파일, 시스템 테이블에서 read() | 예 |
| 에이전트 | 접두사 | 읽기 방식 | 유효함? |
|---|---|---|---|
| Snort | snort | 패킷 캡처에서 recvfrom() | 예 |
| Suricata | suric | 패킷 캡처에서 recvfrom() | 예 |
| Zeek | zeek_ | 패킷 캡처에서 recvfrom() | 예 |
| 에이전트 | 접두사 | 읽기 방식 | 유효함? |
|---|---|---|---|
| auditd | audit | 감사 netlink 소켓에서 read() | 예 |
| audisp | audisp | 감사 디스패치에서 read() | 예 |
| journalctl | journ | 저널 파일에서 read() / pread() | 예 |
| Telegraf | teleg | 메트릭 소스에서 read() | 예 |
| collectd | colle | 시스템 메트릭에서 read() | 예 |
| Metricbeat | metrc | 시스템 메트릭에서 read() | 예 |
| Packetbeat | packe | 네트워크에서 recvfrom() | 예 |
| Winlogbeat | winlo | 이벤트 로그에서 read() | 예 |
| Heartbeat | hbeat | 가동 시간 확인에서 read() / recvfrom() | 예 |
Falco는 eBPF 프로브를 사용하여 커널 이벤트를 캡처하지만, 결정(규칙 매칭, 알림)은 사용자 공간에서 이루어집니다. Falco 프로세스는 read()를 통해 perf/링 버퍼에서 이벤트를 읽습니다. SunnyDayBPF는 읽기가 완료된 후 Falco가 파싱하기 전에 해당 버퍼의 데이터를 수정합니다.```text
Kernel: Falco eBPF probe captures syscall event
|
v
perf buffer (kernel memory)
|
v
User: falco process calls read() on perf fd
|
v <-- SunnyDayBPF modifies buffer here
|
falco parses modified event
|
rule matching on altered data
|
no alert (or wrong alert)
### 취약하지 않은 항목
| 도구 | 이유 | 설명 |
|------|-----|-------------|
| **Cilium Tetragon** | 커널 공간 강제 | 정책 결정 및 종료/거부 작업은 데이터가 사용자 공간에 도달하기 전에 eBPF 프로그램 내에서 발생합니다 |
| **Tracee (Aqua)** | 커널 공간 탐지 | 이벤트 필터링 및 일부 탐지 로직이 커널 eBPF 프로그램에서 실행됩니다 |
| **Kernel audit module** | 커널 공간 로깅 | 감사 기록은 커널에서 생성되지만, auditd 데몬이 `read()`를 통해 읽습니다 (이 단계에서 취약) |
---
## 수정 규칙 (활성 31개)
### 보안 경고 키워드 (8개 규칙)