AtlasVector/Dirty-Frag-CVE-2026-43284

GitHub: AtlasVector/Dirty-Frag-CVE-2026-43284

Stars: 0 | Forks: 0

# DirtyFrag (CVE-2026-43284) - Lab Detection Exercise Report **Classification:** Internal Lab - CyberLAB **Date:** 24 May 2026 **Platform:** Elastic Stack v9.4.1 **Status:** Detection Confirmed ## Table of Contents - [A - Executive Summary](#a---executive-summary) - [B - Full Findings Report](#b---full-findings-report) - [1. Objective and Threat Model](#1-objective-and-threat-model) - [2. Vulnerability Background](#2-vulnerability-background) - [3. Lab Environment](#3-lab-environment) - [4. Phase 1 - Pre-Execution Setup](#4-phase-1---pre-execution-setup) - [5. Phase 2 - Exploit Execution](#5-phase-2---exploit-execution) - [6. Phase 3 - Post-Exploitation Activity](#6-phase-3---post-exploitation-activity) - [7. Phase 4 - Detection Engineering](#7-phase-4---detection-engineering) - [8. Detection Reference](#8-detection-reference) - [9. Key Findings Summary](#9-key-findings-summary) - [10. References](#10-references) ## A - Executive Summary ### What Was Tested A controlled exploitation exercise simulating a post-initial-access adversary using ***DirtyFrag (CVE-2026-43284)***, a Linux kernel privilege escalation vulnerability. The simulated attacker scenario: low-privilege user (`saskia`, uid=1001) obtained via phished credentials attempts to escalate to root on an internal Linux host. The lab used a deliberately vulnerable Ubuntu machine (`ubuntu-vuln`, kernel `6.0.0-22-generic`) isolated from production networks. ### Result: Exploitation Succeeded - Detection Confirmed The attacker achieved full root access (`uid=0`) within the lab environment. The Elastic Security detection stack generated **3 HIGH-severity alerts** (risk score 73) correctly identifying the exploitation chain. However, detection required manual tuning - the out-of-the-box configuration had gaps that would have resulted in missed alerts. ### Risk Statement | Item | Detail | | ---- | ------ | | **Vulnerability** | DirtyFrag - CVE-2026-43284 (xfrm-ESP path), CVE-2026-43500 (RxRPC path) | | **CVSS impact** | Full local privilege escalation to root | | **Affected kernels** | Linux kernel >= January 2017 (9-year lifetime) | | **Affected distros** | Ubuntu 24.04.4, RHEL 10.1, AlmaLinux 10, openSUSE, CentOS Stream 10, Fedora 44 | | **File integrity bypass** | On-disk files unchanged - AIDE, Tripwire, hash monitoring all report clean | | **Public PoC** | Available (V4bel/dirtyfrag on GitHub) | | **Time to root** | < 10 minutes from low-privilege foothold | ### Key Findings 1. **Default `auditd` rules produce no evidence.** Without explicit syscall rules for `socket`, `splice`, and `unshare`, the exploit runs silently - no logs, no alerts. Default Elastic Agent deployment does not add these rules automatically. 2. **Detection required rule tuning.** The published Elastic Security Labs detection logic used `process.parent.pid` as the correlation key. In practice, **DirtyFrag** forks intermediate processes, breaking that correlation. The fix - correlating by `auditd.session` - was identified and implemented during this exercise. 3. **Post-exploitation actions were extensive.** After gaining root, the attacker read `/etc/shadow`, accessed SSH authorized keys, wrote a persistence marker (`/root/pwned.txt`), and initiated network reconnaissance via `nc`. All occurred within 30 minutes of initial access. ### Recommendations | Priority | Action | | -------- | ------ | | **Immediate** | Patch Linux kernel to a fixed version on all hosts. Apply vendor security advisories for Ubuntu, RHEL, AlmaLinux, openSUSE, CentOS, Fedora. | | **Short-term** | Deploy explicit auditd syscall rules for `socket`, `splice`, and `unshare` on all Linux hosts monitored by Elastic Agent. | | **Short-term** | Update EQL detection rules to correlate by `auditd.session` rather than `process.parent.pid` for namespace-manipulation sequences. | | **Ongoing** | Treat privilege escalation alerts with risk score >= 73 as high-priority triage. Current rule fires within seconds of escalation. | ## B - Full Findings Report ### 1. Objective and Threat Model **Objective:** Validate detection coverage for DirtyFrag exploitation in the home lab SOC, identify detection gaps, and produce a corrected detection rule grounded in observed attacker behaviour. **Threat model:** Simulated post-initial-access adversary with phished credentials for a low-privilege user account (`saskia`, uid=1001). Goal: privilege escalation to root via DirtyFrag using the `xfrm-ESP` receive path. Lab execution performed via Proxmox console - functionally equivalent to SSH post-access. Two attacker capability tiers were considered: - **Vanilla (noisy):** exploit run without any evasion - **Evasive (quiet):** reduced noise, deliberate cleanup This exercise covered the vanilla tier. ### 2. Vulnerability Background DirtyFrag is the third in a family of related Linux kernel bugs that all abuse the same root cause: | CVE | Nickname | Introduced | Path | | --- | -------- | ---------- | ---- | | CVE-2022-0847 | Dirty Pipe | - | pipe | | CVE-2026-31431 | Copy Fail | - | splice | | CVE-2026-43284 | DirtyFrag | Jan 2017 (commit `cac2661c53f3`) | xfrm-ESP | | CVE-2026-43500 | DirtyFrag | Jun 2023 (commit `2dc334f1a63a`) | RxRPC | **Root cause:** IPv4/IPv6 datagram append paths did not set `SKBFL_SHARED_FRAG` after `skb_splice_from_iter()` planted a page cache page into a socket buffer (`sk_buff`). The ESP input path then performed in-place crypto on attacker-controlled page cache pages, treating them as ordinary uncloned non-linear skbs. **Exploit primitive:** 4 or 8-byte controlled write into the page cache. Deterministic - no race condition required. **Exploit chain:** **Critical evasion property:** The on-disk file is never modified. File integrity monitoring tools (AIDE, Tripwire, hash checks) all report the target file as clean. **Confirmed vulnerable distributions:** Ubuntu 24.04.4, RHEL 10.1, AlmaLinux 10, openSUSE Tumbleweed, CentOS Stream 10, Fedora 44. ### 3. Lab Environment | Component | Details | | --------- | ------- | | Fleet Server / ELK host | `ubuntu-tm` / `elk-docker` - `172.66.66.30` (lab-internal) | | Elastic Stack | v9.4.1 (Elasticsearch, Kibana, Logstash - Docker) | | Target (victim) host | `ubuntu-vuln` - `172.66.66.27` | | Victim kernel | `6.0.0-22-generic` (vulnerable) | | Victim user | `saskia` - uid=1001, groups=1001(saskia),27(sudo),100(users) | | Elastic Agent | v9.4.1 with auditbeat | | Network IDS | Suricata 8.0.5 on dedicated sensor | | Kibana | `http://172.66.66.30:5601` (lab-internal) | **Active telemetry at exercise time:** | Dataset | Share | | ------- | ----- | | `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% | ### 4. Phase 1 - Pre-Execution Setup #### 4.1 Lab Isolation Lab network isolated before exercise. Firewall alias `Cyber_escape_door` confirmed disabled - preventing lateral reach to other VLANs or internet. ![Lab isolation confirmation](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/308d35a4e8181851.png) #### 4.2 Victim Host Verification Confirmed vulnerable kernel and low-privilege account on `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) ![Kernel and user verification](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/f3756cdd39181857.png) #### 4.3 Stack Health Check **Suricata: running and capturing (systemctl status)** ![Suricata service active and enabled](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/9d5b21fe84181904.png) **Kibana/Elasticsearch: green/healthy (API check)** ![ELK health check via curl returning 302](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/802d1ea4f7181911.png) **VM snapshots taken before any changes** ![ELK VM snapshot - elk-VM-snapshot](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/815c11d44a181918.png) ![Suricata VM snapshot - suricata_pre_dirty_frag (24 May 2026 11:15:53)](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/3e913ff43a181923.png) ![Ubuntu-Vuln-Host snapshot](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/fd9279f3aa181929.png) #### 4.4 Network Capture tcpdump started on Suricata host (`emp6s19`, snapshot length 262144 bytes) for full packet capture of `172.66.66.27` traffic. ![suricata traffic events copy](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/91b87ded44181935.png) ![tcpdump started on Suricata sensor](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/60599ce300181941.png) ### 5. Phase 2 - Exploit Execution #### 5.1 Staging Exploit source (`exp.c`) from V4bel/dirtyfrag PoC staged on victim host. ubuntu-vuln@ubuntu-vuln:~/dirtyfrag$ ls exp exp.c README.md ubuntu-vuln@ubuntu-vuln:~/dirtyfrag$ cp exp.c /tmp/exp/ Right-hand terminal shows the staged copy visible to user `saskia`. ![Exploit source staged in /tmp/exp/](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/ed4fd87b84181947.png) #### 5.2 Compilation Compiled as root via `sudo gcc` (user `saskia` is in 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. ![Exploit compiled - clean_frag binary ready](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/a84c4baad8181954.png) #### 5.3 Execution - Root Gained Exploit executed as `saskia` (uid=1001). The process (`clean_frag`, pid=4326) opened `AF_RXRPC` and `AF_ALG` sockets, then called `splice()` to plant the page cache page into the network buffer. In-place crypto on the ESP path wrote attacker-controlled bytes into the page cache. A child process (pid=4327) called `unshare` with `a0=50000000` (CLONE_NEWUSER | CLONE_NEWNET) to obtain namespace-scoped capabilities. 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):** | Timestamp (UTC) | Syscall | Argument | Process (pid) | User | | --------------- | ------- | -------- | ------------- | ---- | | 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) | All events share `auditd.session=2`. ![Post-exploit root shell obtained](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/9f90b0a8e3182021.png) ### 6. Phase 3 - Post-Exploitation Activity All actions performed as `root` on `ubuntu-vuln` from ~12:22 CEST onward. #### 6.1 Persistence Marker 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 ![Persistence marker written to /root/pwned.txt](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/934b7376a1182029.png) #### 6.2 Credential Access 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 and SSH authorized keys accessed. In a real compromise this enables offline password cracking and persistent SSH backdoor access. ![Credential access - shadow and SSH keys read as root](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/be8589ac90182036.png) #### 6.3 Network Reconnaissance 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. ![Network scan from root - nc against gateway](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/356885933c182044.png) #### 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). ![Suricata events for 172.66.66.27](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/27b0e880ef182050.png) ### 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** (did not fire - see gap below) 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 **Rule 2 - Namespace Manipulation Followed by Privilege Escalation** (fired after fix) 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 Initial Detection Gap - Missing Syscall Coverage Rule 1 returned zero results. Default auditd configuration on `ubuntu-vuln` captured: `write`, `bpf`, `openat`, `unshare` only. Missing: `socket`, `splice`, `bind` - the core exploit primitives. **Remediation:** Added to `/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 events landed in Elasticsearch within seconds of the exploit run. #### 7.3 EQL Correlation Gap - Process Tree Fragmentation Despite events being captured, Rule 2 returned 0 matches. **Root cause - actual process tree (from Elasticsearch):** | Process | PID | PPID | UID | auditd.session | | ------- | --- | ---- | --- | -------------- | | shell (saskia) | 4182 | - | 1001 | 2 | | `clean_frag` (main) | 4326 | 4182 | 1001 | 2 | | `clean_frag` (unshare child) | 4327 | 4326 | 1001 | 2 | | `bash` (root) | - | 4451 | 0 | 2 | The original rule correlated by `process.parent.pid`. The `unshare` event had `ppid=4326`, but the root shell had a different parent - DirtyFrag forks intermediate processes, breaking the correlation. **Fix:** Correlate by `auditd.session`. All events in the exploit chain shared `session=2`, correctly linking the sequence regardless of fork depth. #### 7.4 Alert Result **3 HIGH-severity alerts**, risk score 73, in Kibana Security - Alerts at `2026-05-24T10:25:57Z` UTC (12:25:57 CEST). | Alert | Timestamp (UTC) | Signal | | ----- | --------------- | ------ | | Sequence match - unshare event | 10:25:57.869 | process=clean_frag, user=saskia (uid=1001) | | Sequence match - root shell | 10:25:57.881 | process=bash, user=root (uid=0) | | Composite sequence alert | 10:25:57.893 | host=ubuntu-vuln | - Rule: `DirtyFrag - Namespace Manipulation Followed by Privilege Escalation` - Severity: High - Risk score: 73 - Host: `ubuntu-vuln` ![Kibana alert detail - risk score 73, open status](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/da5b929118182057.png) ![Kibana alert overview - 3 HIGH alerts on ubuntu-vuln](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/acbb6f5edf182103.png) ### 8. Detection Reference #### MITRE ATT&CK Mapping | Tactic | Technique | ID | | ------ | --------- | -- | | Privilege Escalation | Exploitation for Privilege Escalation | T1068 | | Privilege Escalation | Escape to Host | T1611 | | Credential Access | OS Credential Dumping: /etc/passwd and /etc/shadow | T1003.008 | | Discovery | Network Service Discovery | T1046 | #### Key Syscall Values | Syscall | Argument | Meaning | | ------- | -------- | ------- | | `unshare` | `a0=50000000` | CLONE_NEWUSER \| CLONE_NEWNET | | `socket` | `a0=26` | AF_ALG (kernel crypto subsystem) | | `socket` | `a0=21` | AF_RXRPC (RxRPC path) | | `bind` | `socket.family=38` | AF_ALG bind | | `splice` | - | Page injection into network buffers | #### KQL Reference Queries **All dirtyfrag-related auditd events:** data_stream.dataset: "auditd_manager.auditd" and auditd.summary.how: *dirtyfrag* **Namespace manipulation by non-root:** data_stream.dataset: "auditd_manager.auditd" and auditd.data.syscall: "unshare" and auditd.data.a0: "50000000" **Post-escalation root activity in same session:** data_stream.dataset: "auditd_manager.auditd" and user.id: "0" and auditd.session: "2" **All auditd events during exploit window:** data_stream.dataset: "auditd_manager.auditd" and @timestamp >= "2026-05-24T10:20:00Z" and @timestamp <= "2026-05-24T10:30:00Z" **Socket and splice syscalls from exploit process:** data_stream.dataset: "auditd_manager.auditd" and auditd.summary.how: "/tmp/exp/clean_frag" ### 9. Key Findings Summary | # | Finding | Severity | Remediated | | - | ------- | -------- | ---------- | | 1 | Default auditd rules miss `socket`, `splice`, `unshare` - no evidence without explicit rules | Critical | Yes - custom rules deployed to `/etc/audit/rules.d/dirtyfrag.rules` | | 2 | EQL correlation by `process.parent.pid` fails for forked exploit chains | High | Yes - changed to `auditd.session` | | 3 | File integrity monitoring blind to DirtyFrag - on-disk files unchanged throughout | High | No in-scope remediation - patching the kernel is the fix | | 4 | Post-exploitation: shadow file, SSH keys, and network recon all executed as root before any alert-driven response | High | Detected via auditd logs; no dedicated rule fired for credential access or recon phase | ### 10. References - Elastic Security Labs: [Copy Fail and DirtyFrag: Linux Page Bugs in the Wild](https://www.elastic.co/security-labs/copy-fail-dirtyfrag-linux-page-bugs-in-the-wild) - Public PoC: [V4bel/dirtyfrag on GitHub](https://github.com/V4bel/dirtyfrag) - MITRE ATT&CK: [T1068 - Exploitation for Privilege Escalation](https://attack.mitre.org/techniques/T1068/) - MITRE ATT&CK: [TA0004 - Privilege Escalation](https://attack.mitre.org/tactics/TA0004/) - MITRE ATT&CK: [T1003.008 - /etc/passwd and /etc/shadow](https://attack.mitre.org/techniques/T1003/008/)