
DirtyFrag (CVE-2026-43284)에 대한 실험실 탐지 연습 - xfrm-ESP 페이지 캐시 손상을 통한 Linux 커널 권한 상승. 익스플로잇 실행, 탐지 격차 및 Elastic Stack을 사용한 수정된 EQL 규칙을 다루는 종합 분석 보고서.
분류: 내부 실험실 - CyberLAB
날짜: 2026년 5월 24일
플랫폼: Elastic Stack v9.4.1
상태: 탐지 확인됨
제어된 취약점 활용 실습으로, 초기 접근 이후의 공격자가 DirtyFrag (CVE-2026-43284) (리눅스 커널 권한 상승 취약점)을 사용하는 시나리오를 시뮬레이션했습니다. 시뮬레이션된 공격자 시나리오: 피싱된 자격 증명으로 획득한 저권한 사용자 (saskia, uid=1001)가 내부 리눅스 호스트에서 루트로 권한 상승을 시도합니다. 실험실은 프로덕션 네트워크와 분리된 의도적으로 취약한 우분투 머신 (ubuntu-vuln, 커널 6.0.0-22-generic)을 사용했습니다.
공격자는 실험실 환경 내에서 완전한 루트 접근 권한 (uid=0)을 획득했습니다. Elastic Security 탐지 스택은 3개의 HIGH 심각도 알림 (위험 점수 73)을 생성하여 취약점 활용 체인을 올바르게 식별했습니다. 그러나 탐지에는 수동 튜닝이 필요했습니다. 기본 구성을 사용하면 알림을 놓칠 수 있는 공백이 있었습니다.
결론: 커널 <= 6.x를 실행하는 패치되지 않은 리눅스 호스트는 취약합니다. 공격자가 이미 저권한 발판을 가지고 있다면, 이 취약점을 통해 파일 무결성 도구에 보이지 않는 디스크 추적 없이 조용하고 빠르게 완전한 루트 권한을 얻을 수 있습니다.
auditd 규칙은 증거를 생성하지 않습니다. socket, splice, unshare에 대한 명시적인 시스템 호출 규칙이 없으면 취약점 활용이 조용히 실행되어 로그나 알림이 생성되지 않습니다. 기본 Elastic Agent 배포는 이러한 규칙을 자동으로 추가하지 않습니다.process.parent.pid를 사용했습니다. 실제로 DirtyFrag는 중간 프로세스를 포크하여 이 상관 관계를 깨뜨립니다. 수정 사항 - auditd.session으로 상관 관계를 설정하는 방법 - 이 실습 중에 식별되어 구현되었습니다./etc/shadow를 읽고, SSH 인증 키에 접근하고, 지속성 마커 (/root/pwned.txt)를 작성하고, nc를 통해 네트워크 정찰을 시작했습니다. 이 모든 작업은 초기 접근 후 30분 이내에 발생했습니다.목표: 홈 실험실 SOC에서 DirtyFrag 취약점 활용에 대한 탐지 적용 범위를 검증하고, 탐지 공백을 식별하며, 관찰된 공격자 행동에 기반한 수정된 탐지 규칙을 생성합니다.
위협 모델: 피싱된 자격 증명을 통해 저권한 사용자 계정 (saskia, uid=1001)을 획득한 초기 접근 이후의 공격자를 시뮬레이션합니다. 목표: xfrm-ESP 수신 경로를 통해 DirtyFrag를 사용하여 루트로 권한 상승. 실습은 Proxmox 콘솔을 통해 수행되었으며, SSH 사후 접근과 기능적으로 동일합니다.
두 가지 공격자 능력 계층이 고려되었습니다:
이 실습은 Vanilla 계층을 다루었습니다.
DirtyFrag는 동일한 근본 원인을 악용하는 관련 리눅스 커널 버그 계열 중 세 번째입니다:
근본 원인: IPv4/IPv6 데이터그램 추가 경로가 skb_splice_from_iter()가 페이지 캐시 페이지를 소켓 버퍼 (sk_buff)에 심은 후 SKBFL_SHARED_FRAG를 설정하지 않았습니다. 그런 다음 ESP 입력 경로가 공격자가 제어하는 페이지 캐시 페이지에 대해 인플레이스 암호화를 수행하여 일반적인 비복제 비선형 skb로 처리했습니다.
취약점 활용 기본 요소: 페이지 캐시에 4바이트 또는 8바이트 제어 쓰기. 결정적이며 경쟁 조건이 필요하지 않습니다.
취약점 활용 체인:
/usr/bin/su)를 페이지 캐시로 읽음splice()를 통해 패킷을 구성하여 파일 페이지가 struct sk_buff의 frag[0]에 위치하도록 함xfrm-ESP 복호화 경로로 전달execve() 포함)가 손상된 바이트를 반환중요한 회피 속성: 디스크 내 파일은 절대 수정되지 않습니다. 파일 무결성 모니터링 도구 (AIDE, Tripwire, 해시 검사) 모두 대상 파일을 정상으로 보고합니다.
취약한 것으로 확인된 배포판: Ubuntu 24.04.4, RHEL 10.1, AlmaLinux 10, openSUSE Tumbleweed, CentOS Stream 10, Fedora 44.
실습 당시 활성 텔레메트리:
실습 전 실험실 네트워크 격리됨. 방화벽 별칭 Cyber_escape_door 비활성화 확인 - 다른 VLAN 또는 인터넷으로의 측면 연결 차단.

취약한 커널과 저권한 계정이 ubuntu-vuln에 확인됨:```
saskia@ubuntu-vuln:$ uname -r
6.0.0-22-generic
saskia@ubuntu-vuln:$ whoami
saskia
saskia@ubuntu-vuln:~$ id
uid=1001(saskia) gid=1001(saskia) groups=1001(saskia),27(sudo),100(users)

#### 4.3 스택 상태 점검
**Suricata: 실행 중 및 캡처 중 (systemctl 상태)**

**Kibana/Elasticsearch: 녹색/정상 (API 확인)**

**변경 전 VM 스냅샷**



#### 4.4 네트워크 캡처
Suricata 호스트에서 tcpdump 시작 (`emp6s19`, 스냅샷 길이 262144바이트)으로 `172.66.66.27` 트래픽 전체 패킷 캡처.


---
### 5. 2단계 - 익스플로잇 실행
#### 5.1 스테이징
V4bel/dirtyfrag PoC의 익스플로잇 소스(`exp.c`)가 피해자 호스트에 스테이징됨.```bash
ubuntu-vuln@ubuntu-vuln:~/dirtyfrag$ ls
exp exp.c README.md
ubuntu-vuln@ubuntu-vuln:~/dirtyfrag$ cp exp.c /tmp/exp/
오른쪽 터미널은 사용자 saskia에게 보이는 스테이징된 복사본을 보여줍니다.

루트 권한으로 sudo gcc를 통해 컴파일 (사용자 saskia는 sudoers에 있음):```
saskia@ubuntu-vuln:$ sudo gcc -o /tmp/exp/clean_frag /tmp/exp/exp.c
saskia@ubuntu-vuln:$ ls -la /tmp/exp/
-rwxr-xr-x 1 root root 62320 May 24 12:18 clean_frag
-rw-rw-r-- 1 ubuntu-vuln ubuntu-vuln 67803 May 24 12:13 exp.c
saskia@ubuntu-vuln:~$ id
uid=1001(saskia) gid=1001(saskia) groups=1001(saskia),27(sudo),100(users)
Binary: ELF 64-bit LSB executable, x86-64, dynamically linked.

#### 5.3 실행 - 루트 획득
Exploit이 `saskia` (uid=1001)로 실행되었습니다. 프로세스(`clean_frag`, pid=4326)는 `AF_RXRPC` 및 `AF_ALG` 소켓을 열고, `splice()`를 호출하여 페이지 캐시 페이지를 네트워크 버퍼에 심었습니다. ESP 경로의 제자리 암호화(In-place crypto)는 공격자가 제어하는 바이트를 페이지 캐시에 기록했습니다. 자식 프로세스(pid=4327)는 `a0=50000000` (CLONE_NEWUSER | CLONE_NEWNET)으로 `unshare`를 호출하여 네임스페이스 범위의 권한을 획득했습니다.```
saskia@ubuntu-vuln:~$ /tmp/exp/clean_frag
...
root@ubuntu-vuln:~# id
uid=0(root) gid=0(root) groups=0(root)
root@ubuntu-vuln:~# ls
Full root shell obtained at 12:22 CEST (10:22 UTC), 24 May 2026.
Auditd syscall sequence captured (UTC):
All events share auditd.session=2.

ubuntu-vuln에서 ~12:22 CEST 이후부터 root로 수행된 모든 작업.
root@ubuntu-vuln:# echo "Dirty Frag PoC executed at $(date)" > /root/pwned.txt
root@ubuntu-vuln:# cat /root/pwned.txt
Dirty Frag PoC executed at Sun May 24 12:28:05 PM CEST 2026

#### 6.2 자격 증명 접근```bash
root@ubuntu-vuln:~# cat /etc/shadow | head -2
root:*:19823:0:99999:7:::
daemon:*:19823:0:99999:7:::
root@ubuntu-vuln:~# cat /home/ubuntu-vuln/.ssh/authorized_keys
ssh-ed25519 AAAA[...]
Shadow file 및 SSH authorized keys에 접근했습니다. 실제 침해 상황에서는 오프라인 비밀번호 크래킹과 지속적인 SSH 백도어 접근이 가능합니다.

root@ubuntu-vuln:~# nc -vz 172.66.66.1 100-8000
Port scan of the lab gateway (`172.66.66.1`, ports 100-8000) executed from root context at 12:51 CEST. This demonstrates lateral movement capability and network mapping from an escalated session.

#### 6.4 Suricata Network Visibility
Suricata captured **105 events** associated with `172.66.66.27` across the exercise window (88 mdns, 17 flow). At the time the screenshot was taken (during the nc scan at ~12:53 CEST), 29 events were visible in the dashboard.
The DirtyFrag exploit itself is kernel-internal and produces no network signature - the escalation primitive generates no anomalous traffic on the wire. Suricata was engaged to collect pcaps of post-exploitation traffic and enumeration attempts rather than to detect the exploit itself.
| Event Type | Count |
| ---------- | ----- |
| mdns | 88 |
| flow | 17 |
| **Total** | **105** |
The flow events cluster around the nc port scan window (10:50-11:10 UTC / 12:50-13:10 CEST).

---
### 7. Phase 4 - Detection Engineering
#### 7.1 Detection Rules Deployed
Two EQL sequence rules were created in the Kibana Detection Engine based on the Elastic Security Labs article.
**Rule 1 - AF_RXRPC or AF_ALG Socket with Splice Followed by Execution** (실행되지 않음 - 아래 간극 참조)```eql
sequence with maxspan=60s
[any where host.os.type == "linux" and
(
(event.category == "process" and auditd.data.syscall == "socket"
and auditd.data.a0 in ("26", "21")) or
(event.category == "process" and auditd.data.syscall == "splice") or
(event.category == "network" and event.action == "bound-socket"
and data_stream.dataset == "auditd_manager.auditd"
and auditd.data.socket.family == "38")
)
and user.id != "0"] by process.pid, host.id, user.id with runs=10
[process where host.os.type == "linux" and event.action == "executed" and
(
(user.effective.id == "0" and user.id != "0") or
(process.name in ("bash", "sh", "zsh", "dash", "fish", "ksh", "busybox")
and process.args in ("-c", "--command", "-ic", "-ci", "-cl", "-lc",
"-bash", "-sh", "-zsh", "-dash", "-fish", "-ksh"))
)] by process.parent.pid, host.id, user.id
규칙 2 - 네임스페이스 조작 후 권한 상승 (수정 후 실행됨)```eql sequence by host.id, auditd.session with maxspan=30s [process where host.os.type == "linux" and auditd.data.syscall == "unshare" and auditd.data.a0 in ("10000000", "50000000", "70000000", "10020000", "50020000", "70020000") and user.id != "0" and user.id != null] [process where host.os.type == "linux" and user.id == "0" and user.id != null and (process.name in ("bash", "sh", "zsh", "dash", "fish", "ksh", "su", "sudo", "pkexec", "busybox", "mksh") or process.name like ("python*", "perl*", "ruby*", "php*", "lua*"))]
#### 7.2 초기 탐지 격차 - 누락된 시스템 콜 커버리지
Rule 1은 0건을 반환했습니다. `ubuntu-vuln`의 기본 auditd 구성은 `write`, `bpf`, `openat`, `unshare`만 캡처했습니다.
누락: `socket`, `splice`, `bind` - 핵심 익스플로잇 기본 요소입니다.
**해결 방법:** `/etc/audit/rules.d/dirtyfrag.rules`에 다음을 추가:```
-a always,exit -F arch=b64 -S socket -k socket_syscall
-a always,exit -F arch=b32 -S socketcall -k socket_syscall
-a always,exit -F arch=b64 -S splice -k splice-syscall
-a always,exit -F arch=b32 -S splice -k splice-syscall
-a always,exit -F arch=b64 -S unshare -k unshare-syscall
-a always,exit -F arch=b32 -S unshare -k unshare-syscall
272 new auditd 이벤트가 익스플로잇 실행 후 수 초 내에 Elasticsearch에 수집되었습니다.
이벤트가 캡처되었음에도 불구하고 규칙 2는 0개의 일치를 반환했습니다.
근본 원인 - 실제 프로세스 트리 (Elasticsearch 기준):
원래 규칙은 process.parent.pid로 상관 관계를 분석했습니다. unshare 이벤트의 ppid=4326이었지만, 루트 셸은 다른 부모를 가졌습니다. DirtyFrag는 중간 프로세스를 포크하여 상관 관계를 깨뜨렸습니다.
수정: auditd.session으로 상관 관계 분석. 익스플로잇 체인의 모든 이벤트는 session=2를 공유하여 포크 깊이에 관계없이 시퀀스를 올바르게 연결합니다.
3개의 HIGH 심각도 알림, 위험 점수 73, Kibana Security - Alerts, 시간: 2026-05-24T10:25:57Z UTC (12:25:57 CEST).
| 알림 | 타임스탬프 (UTC) | 시그널 |
|---|---|---|
| 시퀀스 일치 - unshare 이벤트 | 10:25:57.869 | process=clean_frag, user=saskia (uid=1001) |
| 시퀀스 일치 - 루트 셸 | 10:25:57.881 | process=bash, user=root (uid=0) |
| 복합 시퀀스 알림 | 10:25:57.893 | host=ubuntu-vuln |
DirtyFrag - Namespace Manipulation Followed by Privilege Escalationubuntu-vuln

| 전술 |
|---|
모든 dirtyfrag 관련 auditd 이벤트:
auditd.data ...
``````kql
data_stream.dataset: "auditd_manager.auditd" and auditd.summary.how: *dirtyfrag*
비루트 사용자의 네임스페이스 조작:```kql data_stream.dataset: "auditd_manager.auditd" and auditd.data.syscall: "unshare" and auditd.data.a0: "50000000"
**동일 세션에서 권한 상승 후 루트 활동:**```kql
data_stream.dataset: "auditd_manager.auditd" and user.id: "0" and auditd.session: "2"
익스플로잇 윈도우 동안의 모든 auditd 이벤트:```kql data_stream.dataset: "auditd_manager.auditd" and @timestamp >= "2026-05-24T10:20:00Z" and @timestamp <= "2026-05-24T10:30:00Z"
**익스플로잇 프로세스의 Socket 및 splice 시스템 콜:**```kql
data_stream.dataset: "auditd_manager.auditd" and auditd.summary.how: "/tmp/exp/clean_frag"
| 항목 | 세부 사항 |
|---|
| 취약점 | DirtyFrag - CVE-2026-43284 (xfrm-ESP path), CVE-2026-43500 (RxRPC path) |
| CVSS 영향 | 로컬 권한 상승을 통한 완전한 루트 권한 획득 |
| 영향을 받는 커널 | 리눅스 커널 >= 2017년 1월 (9년 수명) |
| 영향을 받는 배포판 | Ubuntu 24.04.4, RHEL 10.1, AlmaLinux 10, openSUSE, CentOS Stream 10, Fedora 44 |
| 파일 무결성 우회 | 디스크 내 파일 변경 없음 - AIDE, Tripwire, 해시 모니터링 모두 정상 보고 |
| 공개 PoC | 사용 가능 (V4bel/dirtyfrag on GitHub) |
| 루트 권한 획득 시간 | 저권한 발판에서 < 10분 |
| 우선 순위 | 조치 |
|---|
| 즉시 | 모든 호스트의 리눅스 커널을 패치된 버전으로 업데이트하십시오. Ubuntu, RHEL, AlmaLinux, openSUSE, CentOS, Fedora에 대한 벤더 보안 권고를 적용하십시오. |
| 단기 | Elastic Agent가 모니터링하는 모든 리눅스 호스트에 socket, splice, unshare에 대한 명시적인 auditd 시스템 호출 규칙을 배포하십시오. |
| 단기 | 네임스페이스 조작 시퀀스에 대해 process.parent.pid 대신 auditd.session으로 상관 관계를 설정하도록 EQL 탐지 규칙을 업데이트하십시오. |
| 지속적 | 위험 점수 >= 73인 권한 상승 알림을 우선순위가 높은 삼각(triage) 대상으로 취급하십시오. 현재 규칙은 권한 상승 발생 후 몇 초 내에 알림을 발생시킵니다. |
| CVE | 별명 | 도입 시기 | 경로 |
|---|
| CVE-2022-0847 | Dirty Pipe | - | pipe |
| CVE-2026-31431 | Copy Fail | - | splice |
| CVE-2026-43284 | DirtyFrag | 2017년 1월 (커밋 cac2661c53f3) | xfrm-ESP |
| CVE-2026-43500 | DirtyFrag | 2023년 6월 (커밋 2dc334f1a63a) | RxRPC |
| 구성 요소 | 세부 사항 |
|---|
| Fleet Server / ELK 호스트 | ubuntu-tm / elk-docker - 172.66.66.30 (실험실 내부) |
| Elastic Stack | v9.4.1 (Elasticsearch, Kibana, Logstash - Docker) |
| 대상 (피해자) 호스트 | ubuntu-vuln - 172.66.66.27 |
| 피해자 커널 | 6.0.0-22-generic (취약함) |
| 피해자 사용자 | saskia - uid=1001, groups=1001(saskia),27(sudo),100(users) |
| Elastic Agent | v9.4.1 (auditbeat 포함) |
| 네트워크 IDS | 전용 센서의 Suricata 8.0.5 |
| Kibana | http://172.66.66.30:5601 (실험실 내부) |
| 데이터셋 | 점유율 |
|---|
suricata.eve | 75.2% |
elastic_agent.fleet_server | 10.8% |
elastic_agent | 9.1% |
elastic_agent.filebeat | 1.9% |
elastic_agent.auditbeat | 1.4% |
auditd_manager.auditd | 0.5% |
system.auth | 0.2% |
system.syslog | 0.1% |
| 타임스탬프 (UTC) | 시스템 호출 | 인자 | 프로세스 (pid) | 사용자 |
|---|
| 10:21:11.054 | unshare | a0=50000000 | clean_frag (4327) | saskia (1001) |
| 10:21:11.055 | socket | a0=21 (AF_RXRPC) | clean_frag (4326) | saskia (1001) |
| 10:21:17.403 | socket | a0=26 (AF_ALG) | clean_frag (4326) | saskia (1001) |
| 10:21:17.419 | splice | a0=4 | clean_frag (4326) | saskia (1001) |
| 10:21:17.419 | splice | a0=7 | clean_frag (4326) | saskia (1001) |
| 프로세스 | PID | PPID | UID | auditd.session |
|---|
| shell (saskia) | 4182 | - | 1001 | 2 |
clean_frag (메인) | 4326 | 4182 | 1001 | 2 |
clean_frag (unshare 자식) | 4327 | 4326 | 1001 | 2 |
bash (root) | - | 4451 | 0 | 2 |
| 기법 |
|---|
| ID |
|---|
| 권한 상승 | 권한 상승을 위한 악용 | T1068 |
| 권한 상승 | 호스트로 탈출 | T1611 |
| 자격 증명 접근 | OS 자격 증명 덤프: /etc/passwd 및 /etc/shadow | T1003.008 |
| 탐색 | 네트워크 서비스 탐색 | T1046 |
| 시스템 콜 | 인자 | 의미 |
|---|
unshare | a0=50000000 | CLONE_NEWUSER | CLONE_NEWNET |
socket | a0=26 | AF_ALG (커널 암호화 서브시스템) |
socket | a0=21 | AF_RXRPC (RxRPC 경로) |
bind | socket.family=38 | AF_ALG bind |
splice | - | 네트워크 버퍼로의 페이지 삽입 |
| # | 발견 사항 | 심각도 | 조치 완료 |
|---|
| 1 | 기본 auditd 규칙이 socket, splice, unshare를 누락함 - 명시적 규칙 없이는 증거가 없음 | 심각 | 예 - /etc/audit/rules.d/dirtyfrag.rules에 사용자 정의 규칙 배포됨 |
| 2 | process.parent.pid에 의한 EQL 상관 관계가 포크된 익스플로잇 체인에서 실패함 | 높음 | 예 - auditd.session으로 변경됨 |
| 3 | 파일 무결성 모니터링이 DirtyFrag에 대해 무감각 - 디스크상 파일은 전체 기간 동안 변경되지 않음 | 높음 | 범위 내 조치 없음 - 커널 패치가 해결책임 |
| 4 | 사후 익스플로잇: 섀도 파일, SSH 키, 네트워크 정찰이 알림 기반 대응 전에 모두 루트로 실행됨 | 높음 | auditd 로그를 통해 탐지됨; 자격 증명 접근 또는 정찰 단계에 대한 전용 규칙이 없음 |