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.

#### 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)

#### 4.3 Stack Health Check
**Suricata: running and capturing (systemctl status)**

**Kibana/Elasticsearch: green/healthy (API check)**

**VM snapshots taken before any changes**



#### 4.4 Network Capture
tcpdump started on Suricata host (`emp6s19`, snapshot length 262144 bytes) for full packet capture of `172.66.66.27` traffic.


### 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`.

#### 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.

#### 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`.

### 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

#### 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.

#### 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.

#### 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** (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`


### 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/)