| ID | Technique | Tactic |
|---|---|---|
| T1068 | Exploitation for Privilege Escalation | Privilege Escalation |
| T1548.001 | Setuid and Setgid | Privilege Escalation |
Detection: Linux Dirty Frag Kernel Privilege Escalation
Description
The following analytic detects exploitation of Dirty Frag (CVE-2026-43284 and CVE-2026-43500), a Linux kernel local privilege escalation vulnerability. The exploit corrupts the kernel page cache via the IPsec ESP or RxRPC subsystems using a high-frequency splice() syscall loop, followed by a privilege transition to root in the same audit session. This analytic anchors on the exploit-specific behavioral signature, a sustained splice() spray (50 or more calls within a 60-second window) from an unprivileged process executing from a user-writable path (/home, /tmp, /dev/shm, /var/tmp, /run/user, /root), followed within 5 minutes by execution of a set-uid binary in the same auditd session.
Search
1`linux_auditd`
2type=SYSCALL
3key=splice_user
4exe IN (
5 "/home/*",
6 "/tmp/*",
7 "/var/tmp/*",
8 "/dev/shm/*",
9 "/run/user/*",
10 "/root/*"
11)
12
13
14| bin _time span=60s
15
16| eval user = coalesce(user, auid, AUID)
17
18
19| stats count AS splice_count
20 values(exe) AS spray_binary
21 values(pid) AS spray_pid
22 values(user) AS user
23 earliest(_time) AS spray_start
24 latest(_time) AS spray_end
25 BY auid host ses _time
26
27
28| where splice_count >= 50
29
30
31| join type=inner auid host ses [
32 search `linux_auditd`
33 type=SYSCALL
34 key=process_creation
35 exe IN (
36 "/usr/bin/chfn",
37 "/usr/bin/chsh",
38 "/usr/bin/fusermount3",
39 "/usr/bin/gpasswd",
40 "/usr/bin/mount",
41 "/usr/bin/newgrp",
42 "/usr/bin/passwd",
43 "/usr/bin/su",
44 "/usr/bin/sudo",
45 "/usr/bin/umount",
46 "/usr/lib/dbus-1.0/dbus-daemon-launch-helper",
47 "/usr/lib/landscape/apt-update",
48 "/usr/lib/openssh/ssh-keysign",
49 "/usr/lib/polkit-1/polkit-agent-helper-1"
50 )
51
52
53| stats earliest(_time) AS privesc_time
54 values(exe) AS privesc_binary
55 values(comm) AS privesc_comm
56 values(ppid) AS privesc_ppid
57 BY auid host ses
58]
59
60
61| eval window_secs = privesc_time - spray_end
62
63| where window_secs >= 0 AND window_secs <= 300
64
65
66| `security_content_ctime(spray_start)`
67
68| `security_content_ctime(spray_end)`
69
70| `security_content_ctime(privesc_time)`
71
72
73| rename host AS dest
74
75
76| table dest user auid ses spray_binary spray_pid
77 splice_count spray_start spray_end privesc_binary
78 privesc_comm privesc_ppid privesc_time window_secs
79
80
81| `linux_dirty_frag_kernel_privilege_escalation_filter`
Data Source
| Name | Platform | Sourcetype | Source |
|---|---|---|---|
| Linux Auditd Syscall | 'auditd' |
'auditd' |
Macros Used
| Name | Value |
|---|---|
| security_content_ctime | convert timeformat="%Y-%m-%dT%H:%M:%S" ctime($field$) |
| linux_dirty_frag_kernel_privilege_escalation_filter | search * |
linux_dirty_frag_kernel_privilege_escalation_filter is an empty macro by default. It allows the user to filter out any results (false positives) without editing the SPL.
Annotations
CVE
Default Configuration
This detection is configured by default in Splunk Enterprise Security to run with the following settings:
| Setting | Value |
|---|---|
| Disabled | true |
| Cron Schedule | 0 * * * * |
| Earliest Time | -70m@m |
| Latest Time | -10m@m |
| Schedule Window | auto |
| Creates Finding (Notable) | Yes |
| Rule Title | %name% |
| Rule Description | %description% |
| Notable Event Fields | user, dest |
| Creates Intermediate Finding (Risk Event) | Yes |
Implementation
This analytic requires Linux auditd telemetry forwarded to Splunk via the Splunk_TA_nix add-on with the linux_audit sourcetype (referenced through the linux_auditd macro).
The detection depends on two audit rule keys, both of which are standard in the Neo23x0 recommended ruleset (https://github.com/Neo23x0/auditd) and the existing ESCU Copy Fail analytic (Linux Auditd Copy Fail Privilege Escalation), so no detection-specific custom keys are introduced.
PREREQUISITE 1; splice_user key.
-a always,exit -F arch=b64 -S splice -S vmsplice -F success=1 -F auid>=1000 -F auid!=unset -k splice_user -a always,exit -F arch=b32 -S splice -S vmsplice -F success=1 -F auid>=1000 -F auid!=unset -k splice_user
Operators should baseline splice volume in their environment before enabling. Hosts running heavy zero-copy I/O workloads (specific: web servers, mail transfer agents, container runtimes) may need additional filtering.
PREREQUISITE 2; process_creation key.
-a always,exit -F arch=b64 -S execve -S execveat -F auid>=1000 -F auid!=unset -k process_creation -a always,exit -F arch=b32 -S execve -S execveat -F auid>=1000 -F auid!=unset -k process_creation
Known False Positives
The splice volume threshold (50 calls per 60 seconds from a single process in a user-writable path) is calibrated against the V4bel public PoC, which produces 100-460 splice calls in 90 seconds depending on system state. Legitimate user-mode workloads that may produce splice() calls (web servers, mail transfer agents, language runtimes) typically execute from system paths (/usr/sbin, /usr/bin, /usr/lib) and are excluded by the user-writable path filter. Custom-compiled applications, developer test binaries, or container runtimes executing from /home or /tmp could theoretically reach the volume threshold during legitimate I/O-heavy workloads (large file copies, log rotation, archive operations). Operators should baseline splice volume in their environment before enabling as a notable event. If false positives occur, add an allowlist of trusted binary paths via the linux_dirty_frag_kernel_privilege_escalation_filter macro, or raise the splice_count threshold based on observed legitimate-workload baseline.
Associated Analytic Story
Finding
| Title | Entity Field | Entity Type | Risk Score |
|---|---|---|---|
| Local privilege escalation attempt detected on $dest$ executed by $user$ using $spray_binary$ | dest | system | 50 |
Intermediate Findings
| Message | Entity Field | Entity Type | Risk Score |
|---|---|---|---|
| Local privilege escalation attempt detected on $dest$ executed by $user$ using $spray_binary$ | user | user | 50 |
Threat Objects
| Field | Type |
|---|---|
| spray_binary | process_name |
References
Detection Testing
| Test Type | Status | Dataset | Source | Sourcetype |
|---|---|---|---|---|
| Validation | ✅ Passing | N/A | N/A | N/A |
| Unit | ✅ Passing | Dataset | auditd |
auditd |
| Integration | ✅ Passing | Dataset | auditd |
auditd |
Replay any dataset to Splunk Enterprise by using our replay.py tool or the UI.
Alternatively you can replay a dataset into a Splunk Attack Range
Source: GitHub |
Version: 1