
Cilium Tetragon TracingPolicy를 사용하여 런타임에서 DirtyFrag Linux LPE 체인(CVE-2026-43284 / CVE-2026-43500) 차단
DirtyFrag Linux 권한 상승 체인(CVE-2026-43284 / CVE-2026-43500)을 Cilium Tetragon TracingPolicy로 런타임에 차단합니다. 이 정책은 공개 PoC가 루트를 얻게 해 주는 페이지-캐시 쓰기에 도달하기 전, 소켓 설정 단계에서 SIGKILL로 종료합니다.
이것의 정체. 랩 기록(writeup)입니다. 처음으로 Tetragon을 설치하고, 실제이고 현재 위협인 커널 LPE를 실제로 막을 수 있는지 확인하고 싶었습니다. 결론적으로 막을 수 있었습니다. 이 문서는 제가 실제로 실행한 것, 실제로 발화한 것, 그리고 그 결과가 증명하는 한계를 정확히 기록합니다. 이는 패치를 대체하지 않습니다.
파일: 이 README(단일 문서, 증거 포함) · block-dirtyfrag.yaml(정책)
| Exploit | DirtyFrag - 공개 PoC: V4bel/dirtyfrag |
| CVEs | CVE-2026-43284 (xfrm-ESP 페이지-캐시 쓰기), CVE-2026-43500 (RxRPC 페이지-캐시 쓰기) |
| 호스트 | Ubuntu 24.04.4 LTS, Tetragon v1.7.0 (standalone, systemd) |
기준 - 정책 없음, 커널 6.8.0-88 (취약) | PoC → uid=0(root) |
정책 적용 시 - 커널 6.8.0-88 | PoC가 socket(AF_RXRPC)에서 SIGKILL 처리됨; 사용자는 uid=1000 유지 |
패치된 커널 6.8.0-134 | PoC는 자체적으로 실패(rc=4); 소켓 훅은 여전히 발화, 탐지이지 완화가 아님 (참고) |
| 제어의 성격 | 보완 통제 / 가상 패치, 커널 수정 아님 |
DirtyFrag는 Linux 커널의 두 개의 독립적인 페이지-캐시 쓰기 프리미티브로 구성된 로컬 권한 상승 체인입니다. 하나는 xfrm/ESP(IPsec) 제자리 복호화 경로(CVE-2026-43284), 다른 하나는 RxRPC 경로(CVE-2026-43500)에 있습니다. 각각 권한 없는 로컬 사용자가 읽기 전용 페이지-캐시 페이지, 예를 들어 /bin/su 같은 setuid-root 바이너리의 캐시된 이미지에 공격자가 제어하는 바이트를 쓸 수 있게 하며, 그로부터 루트를 얻을 수 있습니다. 쓰기는 메모리에만 기록되고 디스크의 파일은 절대 수정되지 않으므로 파일 무결성 모니터링은 아무것도 볼 수 없습니다. Dirty Pipe 및 Copy Fail과 동일한 버그 클래스입니다. 두 CVE는 의도적으로 연결됩니다. 주어진 환경에서 한 경로를 사용할 수 없으면 다른 경로가 여전히 작동합니다.
이 호스트에서는 비특권 사용자 네임스페이스가 AppArmor(kernel.apparmor_restrict_unprivileged_userns = 1)로 제한되어 체인의 ESP 절반을 차단합니다. 그로 인해 남는 것은 RxRPC 경로이며, 이는 AF_RXRPC 소켓(주소 패밀리 33)을 여는 것입니다. 그리고 이 정책이 죽이는 단계가 바로 그것입니다.
실제 수정은 패치된 커널입니다. 여기의 모든 것은 아직 패치할 수 없는 호스트를 위한 임시 조치입니다. 우분투는 이 테스트 이전에 DirtyFrag 수정을 배포했으므로, 이는 라이브 0-day가 아니라 알려진 N-day입니다. 요점은 어떤 이유로든 여전히 취약한 커널을 실행 중인 호스트에서 런타임 제어가 무엇을 할 수 있는지 보여주는 것입니다.
전체 정책: block-dirtyfrag.yaml. 두 개의 kprobe를 설치합니다.
훅 1 - 소켓 준비 (sys_socket). 핵심 제어. 익스플로잇의 RxRPC 경로는 커널 모듈이 이미 로드되었는지 여부와 관계없이 매번 socket(AF_RXRPC, …)를 호출해야 합니다. 정책은 주소 패밀리를 매칭합니다:
AF_RXRPC) → Sigkill. AFS 클라이언트가 아닌 호스트에서는 사실상 합법적인 것이 AF_RXRPC 소켓을 열지 않으므로, 여기서의 전면 차단은 안전하고 신뢰도가 높습니다.AF_ALG) → Post (감사 전용, 죽이지 않음). AF_ALG는 사용자 공간 커널-암호화 API이며 실제 합법적 사용자(cryptsetup, libkcapi 도구, 일부 FIPS 워크플로)가 있습니다. 패밀리만으로 죽이면 오탐이 발생하므로 이 경로는 로그만 남깁니다. 집행 경로는 다음과 같습니다. 한동안 감사하고, 실제 관찰된 바이너리로 NotIn 허용 목록을 만든 다음 Sigkill로 승격하는 것을 고려합니다.훅 2 - 취약한 모듈 자동 로드 (security_kernel_module_request). 심층 방어. 커널이 취약한 모듈 패밀리(esp4, esp6, rxrpc, net-pf-33/net-pf-38 소켓 별칭, pcbc/fcrypt 암호화 템플릿)를 자동으로 로드하도록 요청받을 때 발화합니다. 제한 사항: 모듈이 이미 상주하지 않은 경우에만 발화합니다. 부팅 후 첫 익스플로잇 실행 이후에는 해당 모듈이 로드되어 이 훅은 조용해집니다. 콜드 부팅 계층일 뿐 기본 제어는 아닙니다.
함께: 훅 1은 모듈이 웜이든 콜드든 익스플로잇을 잡습니다. 훅 2는 콜드 호스트에서 더 이르고 더 구체적인 트립을 추가합니다.
6.8.0-88-generic에서 나온 것입니다 (기준에서는 루트에 도달합니다). 상자에는 패치된 커널인 6.8.0-134-generic도 설치되어 있으며, 이것은 직접 확인되었습니다. -134로 재부팅하면 PoC는 정책 유무와 관계없이 자체적으로 실패합니다(rc=4, 루트 없음) (아래 참고). 완화 데모를 재현하려면 GRUB에서 6.8.0-88로 부팅하십시오 (여전히 설치되어 있음). 패치된 커널에서는 완화할 것이 없습니다.AF_ALG 경로에 대해 대표 워크로드를 대상으로 감사 모드로 먼저 실행하십시오.lockdown,capability,landlock,yama,apparmor — bpf 없음). 따라서 집행은 인커널 LSM 거부가 아니라 kprobe에서 Sigkill을 사용합니다. 킬은 쓰기 프리미티브 이전의 socket() 시스템 콜에 도달하므로, "취약점 자체를 차단"하는 것이 아니라 필수 초기 단계에서 프로세스를 종료합니다.1~5단계는 모두 동일한 6.8.0-88 부팅에서 이루어집니다 (취약한 커널).
1. 환경 - Ubuntu 24.04.4, 커널 6.8.0-88-generic, systemd에서 Tetragon v1.7.0 활성, 비특권 userns 제한.
$ uname -r
6.8.0-88-generic
$ tetra version
CLI version: v1.7.0
$ systemctl is-active tetragon
active
2. 사전 조건 (정책 OFF) - 깨끗한 시작점: 취약한 모듈이 상주하지 않음, xfrm 상태 없음, 로드된 정책 없음.
$ lsmod | grep -E 'esp4|esp6|rxrpc' || echo "(none loaded)"
(none loaded)
$ sudo ip xfrm state # (empty)
$ sudo tetra tp list
ID NAME STATE FILTERID NAMESPACE SENSORS KERNELMEMORY MODE NPOST NENFORCE NMONITOR
3. 기준 (정책 OFF) - 익스플로잇이 작동합니다. 이것은 커널이 실제로 취약하다는 것을 증명합니다. 전체 문서가 여기에 기반합니다.
$ ./exp ; id
uid=0(root) gid=0(root) groups=0(root)
4. 정책을 로드합니다.
$ sudo tetra tp add /etc/tetragon/tetragon.tp.d/block-dirtyfrag.yaml
tracing policy "…/block-dirtyfrag.yaml" added
5. 강제 적용 (정책 ON) - 킬. 익스플로잇은 socket() 호출에서 시그널에 의해 종료되며 su에 도달하지 못합니다:
🚀 process /home/…/dirtyfrag/exp
❓ syscall /home/…/dirtyfrag/exp __x64_sys_socket
Kernel:
0x0: __x64_sys_socket+0x5
0x0: do_syscall_64+0x7f
0x0: entry_SYSCALL_64_after_hwframe+0x78
💥 exit /home/…/dirtyfrag/exp SIGKILL
구조화된 이벤트는 매치와 킬을 모두 확인합니다 - 소켓 syscall에 대한 process_kprobe, 동일한 PID에 대한 시그널에 의한 process_exit:
// process_kprobe — the AF_RXRPC match
{ "process_kprobe": {
"process": { "pid": 24083, "uid": 1000, "binary": ".../dirtyfrag/exp" },
"function_name": "__x64_sys_socket",
"args": [ { "int_arg": 33, "label": "family" } ],
"policy_name": "block-dirtyfrag",
"action": "KPROBE_ACTION_POST"
} }
// process_exit — same PID, killed by signal
{ "process_exit": {
"process": { "pid": 24083, "binary": ".../dirtyfrag/exp" },
"signal": "SIGKILL"
} }
kprobe의 action이 KPROBE_ACTION_POST로 읽히는 이유는 Post 액션이 보이는 이벤트를 발생시키기 때문입니다. Sigkill 액션은 별도의 SIGKILL 종료를 생성합니다. 두 이벤트가 함께 증거입니다. 매치 그리고 킬.
참고: 원시
07캡처에는 정책의 이전 개정판(AF_ALG경로가 감사 전용으로 분리되기 전)의message문자열도 포함되어 있습니다.family: 33매치와 그로 인한SIGKILL은 개정판과 관계없이 동일합니다. 다른 점은 그 텍스트뿐입니다.
취약 커널 실행 후 호스트를 6.8.0-134-generic(Ubuntu의 패치된 커널)로 재부팅하고 PoC를 다시 실행했습니다:
$ ./exp # policy OFF
dirtyfrag: failed (rc=4) # exploit fails on its own — no root
$ ./exp # policy ON
Killed # SIGKILL at socket(AF_RXRPC)
이것이 무엇을 보여주는지 정확히 하자면:
rc=4, 루트 없음). 커널이 패치되었기 때문입니다. 정책이 막을 것이 없습니다. 완화 주장을 담은 전/후 비교는 취약한 -88 커널에서만 존재합니다.socket(AF_RXRPC)를 호출하므로 Tetragon은 패치된 커널에서도 패치되지 않은 커널과 마찬가지로 여전히 SIGKILL을 보내고 로그에 시도를 표시합니다. 이는 시도 탐지와 심층 방어로서 가치가 있지만, 작동 중인 익스플로잇을 멈추는 것과는 같지 않습니다.AF_RXRPC가 합법적이며 전면 차단은 이를 깨뜨릴 것입니다. 노드별로 확인하십시오.AF_ALG 경로는 설계상 감사 전용입니다. 모듈이 이미 웜인 상태에서 오직 AF_ALG 경로만 사용하는 변형은 허용 목록 후 해당 경로를 집행으로 승격할 때까지 로그만 남기고 죽이지 않습니다.AF_RXRPC 소켓이 쓰기 프리미티브보다 먼저 열리기 때문에 작동합니다. 그 순서가 조기 킬을 효과적으로 만드는 것입니다. 모든 가능한 익스플로잇에 대한 보장은 아닙니다.설정: Tetragon v1.7.0 standalone, systemctl로 시작; 정책은 tetra tracingpolicy add로 로드됨.