~/f4n6 $ grep -r "Linux Detection Engineering - Local Privilege Escalation" ./investigations/ --include="*.md"

Linux Detection Engineering - Local Privilege Escalation

Jeff Davies 11 Sep 2026 13 min read

1. Executive summary

Elastic Security Labs has published a detection-engineering framework for Linux local privilege escalation (LPE), validated against 11 public proof-of-concept exploits and 2 SUID misconfigurations from the 2026 disclosure wave. The central finding is that seven of the 13 Linux LPE disclosures Elastic tracked in 2026 share a single bug class — a copy-on-write or zero-copy path writing into data it was supposed to copy first — aimed at different kernel interfaces (AF_ALG/crypto, ESP, RxRPC, socket-buffer fragment helpers, traffic control, filesystem). No verified CVE reference data was resolved for this item, so no CVSS scores, severities, or CISA-KEV exploitation states can be asserted here; the CVEs named in the source (CVE-2026-31431, CVE-2026-43284, CVE-2026-43500, CVE-2026-43503, CVE-2026-46333) are single-sourced to the Elastic blog and its cited research. There is no indication of in-the-wild exploitation, ransomware, or data extortion in the source material — this is a defensive detection framework, not an incident report. The bottom-line risk for EMEA financial services is that Linux server estates — including container hosts and any platform where an attacker can obtain an unprivileged foothold (web shell, compromised service account, phished developer) — face a rising volume of LPE paths that per-CVE detection cannot keep pace with; outcome-oriented detection of the "unprivileged exec from writable path → uid_change to 0" flow is the durable control.

2. Regulatory framing

No specific DORA/NIS2 article is directly engaged by this item. This is a vendor detection-framework publication describing publicly disclosed vulnerabilities and lab-validated PoCs, with no incident, no client-side compromise, and no third-party provider failure in evidence. Generic mappings to incident-reporting or patching articles would be compliance-checkbox padding.

3. Technical analysis & attack chain

The general LPE flow (confirmed across all 13 test cases). Nearly every Linux LPE, regardless of the underlying bug, produces the same host-level skeleton:

  1. An unprivileged user (uid != 0) executes something — usually a freshly dropped or compiled binary, a script, or a shell one-liner — from a writable location: /tmp, /dev/shm, /var/tmp, /home, or /run/user/.
  2. Moments later, a process in that lineage runs as root: a uid_change to 0, an effective uid/gid of 0, or an interactive root shell.
  3. In many PoCs, the exploit confirms success by running whoami, id, or logname.

The 2026 bug-class convergence. Seven of 13 tracked disclosures share one class: a copy-on-write or zero-copy path that writes into data it was supposed to copy first. The mechanism: Linux moves file-backed page-cache pages through kernel subsystems without copying them (via splice(), sendfile()); when a subsystem writes in place without honouring copy-on-write, an unprivileged user corrupts the in-memory image of a privileged file. The file on disk stays clean; the cached version of /usr/bin/su, /bin/su, or another privileged target is not what the administrator expects. Elastic explicitly draws the lineage from DirtyCOW and Dirty Pipe into the 2026 wave.

Per-technique detail (from Elastic's lab runs of public PoCs)

  • Copy Fail (CVE-2026-31431, single-sourced). Chains an AF_ALG socket with splice() to land a controlled write into a page-cache page, then abuses the corruption against a privileged file. Public write-ups describe the vulnerable path as the authencesn AEAD implementation mishandling input manipulated through splice(). Observed path: AF_ALG socket() and splice() burst → cached /usr/bin/su corrupted → su executes with root effective UID. This is the one variant with both a primitive-level signal (auditd: non-root process producing a burst of socket(AF_ALG) calls interleaved with splice()) and an outcome signal.
  • DirtyFrag. Chains the xfrm-ESP Page-Cache Write issue (CVE-2026-43284, single-sourced) with the RxRPC Page-Cache Write issue (CVE-2026-43500, single-sourced). Shared socket-buffer fragments reach in-place writers without the kernel forcing a safe copy. Observed: no distinct primitive alert; shared page-cache fragments reach in-place processing → /bin/su executes with root effective UID.
  • Fragnesia. Targets skb_segment() in net/core/skbuff.c. During GSO segmentation, skb_segment() propagates SKBFL_SHARED_FRAG from the head skb but not from a frag_list member carrying page-cache-backed fragments; once the marker is lost, the resulting skbs pass the ESP skip_cow guard and are decrypted in place over page-cache pages. Trigger is networking-heavy: namespaces, veth pairs, send(), splice(), GRO coalescing, GSO segmentation, ESP-in-TCP receiver. Observed: local compilation (./skb_segment_exploit) and network activity → skb_segment() loses the shared-fragment marker → ESP-in-TCP modifies cached /usr/bin/su, corrupted image executes.
  • DirtyDecrypt (aka DirtyCBC per the PoC authors). An rxgk page-cache write from a missing copy-on-write guard in rxgk_decrypt_skb(): the function builds an skb scatterlist and calls Kerberos decryption without forcing a safe copy, while the krb5enc AEAD template decrypts in place before the HMAC check. The PoC sets up user and network namespaces, drives RxRPC over loopback, splices file-backed pages into the packet path, repeatedly fires the decrypt primitive, targets a readable SUID-root binary (e.g. /usr/bin/su), backs it up under /tmp, corrupts the in-memory image with a small setuid(0) + /bin/sh payload, and executes it. Observed binary: ./dirtydecrypt.
  • pedit COW. The abused interface is the tc packet-editing action act_pedit. tcf_pedit_act() computes the COW range once before the key loop and can leave part of the write region un-COW'd (NVD description quoted by Elastic: "net/sched: fix pedit partial COW leading to page cache corruption"). The PoC calls unshare() internally and configures act_pedit through Netlink; the write extends beyond the copied region, the cached su entry point is replaced, and execution yields a root shell.
  • DirtyClone (CVE-2026-43503, single-sourced). NVD describes missing propagation of SKBFL_SHARED_FRAG through helpers such as __pskb_copy_fclone() and skb_shift(), letting an unprivileged user write into the page cache of a root-owned read-only file through later in-place writers. Python-driven, runs from a user-controlled working directory, crosses into root. Elastic explicitly cautions: confirm whether the observed uid_change represented host root or namespace-mapped root before describing it as completed host escalation.
  • CIFSwitch. A trusted-helper bug reached through the kernel: missing validation in the cifs.spnego key type. The attacker calls request_key() with a forged key description, causing the kernel to invoke the root-owned cifs.upcall helper with attacker-controlled fields. With upcall_target=app, the helper enters the attacker's mount namespace and performs a getpwuid() lookup before dropping privileges — loading an attacker-controlled NSS library and executing code as root. Observed: unshare creates a hostile mount namespace → forged cifs.spnego request launches root-owned cifs.upcall → helper loads attacker-controlled NSS code and writes a sudoers rule.
  • OVSwrap. Uses a private user and network namespace to reach a vulnerable kernel interface directly: unshare -Urn grants namespace-local CAP_NET_ADMIN, allowing creation of a private Open vSwitch datapath without host-level CAP_NET_ADMIN. The bug is in OVS action handling: the nla_len field describing an individual Netlink attribute is 16 bits wide; before the fix, a generated nested action could grow beyond 65,535 bytes without rejection, the stored length wraps, and later OVS parsing resumes from attacker-controlled data inside the generated action stream. The PoC builds kernel read and targeted decrement primitives, locates a host-side process and its credentials, and modifies its fsuid/fsgid until the process can write as root — then writes a passwordless sudo rule and executes sudo -n bash.
  • ptrace_may_dream (CVE-2026-46333, single-sourced). The bug sits in the kernel's __ptrace_may_access() path: during process exit there is a window when a task has dropped its memory image but still holds open file descriptors. Paired with pidfd_getfd(), an unprivileged process can duplicate descriptors from a dying privileged process when credential checks line up. Qualys (as cited by Elastic) described impact as credential disclosure and root-code-execution potential, with case studies against chage, ssh-keysign, pkexec, and accounts-daemon. Critically, a successful exploit may never create a root shell — root-only material simply leaves the boundary. Two sub-PoCs:
  • ssh-keysign-pwn (./sshkeysign_pwn): repeatedly spawns /usr/lib/openssh/ssh-keysign (which opens SSH host private keys before dropping privileges), opens a pidfd for the child, races pidfd_getfd() across likely descriptors, and checks whether any duplicated descriptor points to an ssh_host_*_key file. No root shell.
  • chage_pwn (./chage_pwn root): forks chage -l <user> (which opens /etc/shadow then drops privileges), races pidfd_getfd() over candidate descriptors, finds the duplicated descriptor pointing at /etc/shadow, and reads it. The meaningful transition is group-based: the unprivileged process enters shadow group context.
  • A third observed path in the test matrix: busctl --system call triggers AccountsService activity → pidfd_getfd() race duplicates a root-authenticated D-Bus socket → account shell, password, and administrator status changed before su/sudo yields root.
  • SUID misconfigurations (no CVE). (a) Root-owned SUID find executes /bin/sh -p through -exec; the shell retains root effective UID. (b) System Bash copied to a non-standard path with SUID set; bash -p preserves the elevated effective UID → root-capable shell.

Namespace precursor. A large family of LPEs begins with unshare(CLONE_NEWUSER) to gain capabilities inside a new user namespace, then uses that borrowed power to reach kernel code paths (filesystems, mounts, networking) never designed for untrusted local input. This step is shared across CIFSwitch, pedit COW, DirtyClone, and container escapes, making it a high-value early detection point independent of whichever bug follows.

LLM-assisted research trend (single-sourced to the Elastic blog's characterisation). Elastic reports that Qualys attributes RefluXFS to a research effort with Anthropic, pointing "Claude Mythos Preview" at the kernel's memory-management and filesystem code to hunt for a DirtyCOW-style race, with humans on validation and disclosure; the OVSwrap author credits a comparable LLM-assisted workflow. Adverse Trace note: this attribution of research methodology is single-sourced and concerns vulnerability research, not threat-actor activity — no malicious actor is named anywhere in the source material, and no MITRE-profiled actor attribution exists for any of these bugs.

Confidence caveat. All technical detail above derives from a single vendor publication (Elastic Security Labs) and the public PoCs it references. CVE identifiers, NVD descriptions, and Qualys impact statements are quoted through Elastic, not independently verified by Adverse Trace for this advisory. Verify before enforcement.

4. Mitigation & containment

This is a detection-framework item, not an active incident; there is no vendor fix named in the source for the individual kernel bugs. Actions are therefore hardening and detection-deployment oriented.

P1 — within 24 hours

  • Audit SUID/SGID surface on all Linux hosts. Enumerate setuid-root binaries (find / -perm -4000 -type f 2>/dev/null) and remove the SUID bit from any interactive-capable binary on the GTFOBins class list (find, gdb, vim, dd, nmap, and similar). The source's two misconfiguration cases — SUID find -exec and a copied SUID bash -p — are instant-root one-liners with no CVE required.
  • Deploy outcome-oriented LPE detection. If running Elastic: in Kibana, navigate to Security → Rules → Detection rules (SIEM), install the Elastic prebuilt rules, and enable the Linux privilege escalation ruleset (filter tags OS: Linux and Tactic: Privilege Escalation). Deploy Elastic Defend on Linux hosts for behavioural coverage. Detection rules live in Elastic's detection-rules repository; endpoint rules in protections-artifacts.
  • Enable syscall-level visibility. Enable the Auditd Manager integration. The page-cache class specifically relies on socket, splice, and bind auditing, plus execve. The Copy Fail and DirtyFrag research lists the exact auditd rules to add.

P2 — within 72 hours

  • Prioritise the named detection rules by the coverage they provided in Elastic's validation runs: Suspicious SUID/SGID Utility Execution (fired on Copy Fail and DirtyFrag finishes), General Privilege Escalation Sequence Detected (lowest false-positive, highest true-positive for public PoCs — lead investigations with it), Potential Privilege Escalation via Python Exploit / Suspicious UID Change to Root via Python (caught DirtyClone and OVSwrap where no per-CVE tell existed), Namespace Manipulation Using Unshare (early precursor for CIFSwitch, pedit COW, OVSwrap, container escapes), Potential Copy Fail (CVE-2026-31431) Exploitation via AF_ALG Socket (primitive-level), and Potential Shadow Read via Unprivileged User (chage_pwn descriptor theft).
  • Tune the writable-path exec rules. Elastic notes the exec-then-elevate correlation rules fire on false positives (benign precompiled binaries in /tmp or /home elevating) and require environment-specific tuning; on static server estates they should be near plug-and-play. The Python uid_change rule uses a new-terms rule type (command line not seen on the host.id in the last five days) to control noise — replicate this pattern in non-Elastic tooling.
  • Restrict namespace creation where feasible. unshare(CLONE_NEWUSER) is the shared precursor across multiple 2026 techniques and container escapes. Where workloads do not require user namespaces, disable via sysctl (kernel.unprivileged_userns_clone=0 on distros exposing it, or equivalent AppArmor/seccomp policy). Note: this will break container tooling and sandboxing that legitimately call unshare — apply to server estates selectively.

P3 — within 7 days

  • Patch mechanism, not per-CVE tracking. The source's core argument: when one bug class can be aimed at a dozen kernel interfaces in a quarter, per-CVE detection arrives late. Track and patch the kernel page-cache/COW class as a family (Copy Fail, DirtyFrag, Fragnesia, DirtyDecrypt, DirtyClone, pedit COW, RefluXFS) rather than triaging each advisory in isolation; ensure kernel update cadence on all Linux hosts including container hosts, since several of these primitives are reachable from inside containers via namespace capabilities.
  • Protect the descriptor-theft class. For CVE-2026-46333-style attacks, the source indicates the loss is root-only material leaving the boundary (SSH host private keys, /etc/shadow, authenticated D-Bus sockets) with no root shell. Verify: SSH host key file permissions and locations (ssh_host_*_key), /etc/shadow read auditing for non-root/non-shadow-group processes, and alerting on busctl --system call from interactive user contexts.
  • Validate in a lab. Reproduce each technique in a disposable VM using the relevant public PoC — treat all exploit code as lab-only, never run against systems you do not own.

5. Indicators of compromise

No indicators of compromise available in the source material. This advisory covers publicly disclosed vulnerabilities and lab-validated PoCs; no malicious campaign, actor infrastructure, or in-the-wild artefacts are described.

Behavioural indicators (from Elastic's lab telemetry; these describe exploit behaviour, not confirmed adversary activity):

Behaviour Where to observe Confidence
Non-root process burst of socket(AF_ALG) calls interleaved with splice() auditd syscall logs High (Copy Fail primitive)
unshare creating user/network namespace from non-root user, followed by uid_change to 0 in same lineage EDR process telemetry, auditd High (CIFSwitch, pedit COW, OVSwrap, DirtyDecrypt precursor)
Exec from writable path (/tmp, /dev/shm, /var/tmp, /home/*, /run/user/*) followed by uid_change to 0 under same parent EDR process lineage High (general LPE flow)
SUID helper (su, sudo, pkexec, passwd) executed with argument count ≤1, euid 0, real user non-root, from interpreter/shell-one-liner/writable-path parent EDR process telemetry High
Python interpreter uid_change to 0 from world-/user-writable working directory, non-root parent, command line unseen on host in 5 days EDR new-terms telemetry High (DirtyClone, OVSwrap)
Repeated spawning of ssh-keysign or chage -l from a recently compiled binary in user directory (pidfd_getfd race) EDR process telemetry High (CVE-2026-46333 class)
Unprivileged process entering shadow group context from user-controlled executable path EDR group-transition telemetry High (chage_pwn)
busctl --system call from unprivileged interactive context EDR process telemetry High (ptrace_may_dream)
Recently compiled executable making local network connections, then SUID execution with root euid EDR + network telemetry Medium (Fragnesia-style staging)
Sudoers file modification following namespace/mount activity File integrity monitoring High (CIFSwitch, OVSwrap finish)

6. Detection

The source provides genuine threat artefacts: PoC binary names, exact SUID helper paths, command-line shapes, and target file paths. Rules below use only strings present in the source.

rule Linux_LPE_2026_PoC_Binaries_Elastic_Lab
{
    meta:
        author = "Adverse Trace"
        date = "2026-09-11"
        reference = "https://www.elastic.co/security-labs/threat-command/linux-privilege-escalation-detection-framework"
        description = "Matches binary/script names of public 2026 Linux LPE PoCs observed in Elastic Security Labs validation runs. Lab artefacts; useful for retro-hunt on production estates to find unauthorised exploit staging."
    strings:
        $poc1 = "skb_segment_exploit" ascii
        $poc2 = "dirtydecrypt" ascii
        $poc3 = "sshkeysign_pwn" ascii
        $poc4 = "chage_pwn" ascii
    condition:
        uint32(0) == 0x464c457f and 2 of them
        or filesize < 200KB and 2 of them
}

Note: the four PoC names are the only exploit binary names given in the source. The uint32(0) == 0x464c457f check matches ELF magic; the filesize fallback covers script-form PoCs (e.g. Python-driven DirtyClone/OVSwrap were not named, so they are not included — do not extend the list speculatively).

title: Linux LPE - SUID helper executed with minimal arguments from writable path parent
id: 4c1a7f52-9d3e-4b18-a6f2-1e5d8c9b7a30
status: experimental
description: >
  Detects the privilege shape Elastic identified as the most common LPE finish:
  a setuid-root helper (su, sudo, pkexec, passwd) running with effective uid 0
  while the real user is non-root, invoked with minimal arguments from an
  interpreter, shell one-liner, or writable-path parent. Maps to ATT&CK
  T1548.001 (Abuse Elevation Control Mechanism: Setuid and Setgid).
references:

  - https://www.elastic.co/security-labs/threat-command/linux-privilege-escalation-detection-framework
author: Adverse Trace
date: 2026-09-11
tags:

  - attack.privilege_escalation
  - attack.t1548.001
logsource:
    product: linux
    service: auditd
detection:
    selection_helper:
        exe|endswith:

            - '/bin/su'
            - '/usr/bin/su'
            - '/bin/sudo'
            - '/usr/bin/sudo'
            - '/usr/bin/pkexec'
            - '/usr/bin/passwd'
    selection_euid_root:
        euid: 0
    filter_real_user:
        uid: 0
    selection_min_args:
        a0|endswith:

            - '/bin/su'
            - '/usr/bin/su'
            - '/bin/sudo'
            - '/usr/bin/sudo'
            - '/usr/bin/pkexec'
            - '/usr/bin/passwd'
    condition: selection_helper and selection_euid_root and not filter_real_user
falsepositives:

    - Legitimate sudo usage by users (typically carries additional arguments;
      argument-count filtering reduces this)
level: high
title: Linux LPE - unshare user namespace creation by non-root user
id: 8f2b4d61-c7a9-4e30-b5d1-2f6e0a8c4d92
status: experimental
description: >
  Detects unshare creating a user namespace from a non-root user - the shared
  precursor across CIFSwitch, pedit COW, DirtyClone, OVSwrap and container
  escapes per Elastic Security Labs. Correlate with subsequent uid_change to 0
  in the same lineage to reduce false positives from sandboxing and container
  tooling, which call unshare constantly but rarely transition to root.
references:

  - https://www.elastic.co/security-labs/threat-command/linux-privilege-escalation-detection-framework
author: Adverse Trace
date: 2026-09-11
tags:

  - attack.privilege_escalation
  - attack.t1611
logsource:
    product: linux
    service: auditd
detection:
    selection:
        exe|endswith: '/usr/bin/unshare'
        key|contains:

            - 'CLONE_NEWUSER'
            - '-U'
            - '--user'
    filter_root:
        uid: 0
    condition: selection and not filter_root
falsepositives:

    - Container runtimes, sandboxing tooling, development environments
level: medium
title: Linux LPE - pidfd_getfd descriptor race against SUID helpers (CVE-2026-46333 class)
id: b3d5e9a2-1f4c-6d80-9b2e-7a1c5f8d3e60
status: experimental
description: >
  Detects repeated execution of ssh-keysign or chage from a recently compiled
  or user-writable-path parent - the observable shape of the ptrace_may_dream
  pidfd_getfd() exit-race PoCs (sshkeysign_pwn, chage_pwn). A successful
  exploit may never produce a root shell; the loss is duplicated descriptors
  to SSH host private keys or /etc/shadow.
references:

  - https://www.elastic.co/security-labs/threat-command/linux-privilege-escalation-detection-framework
author: Adverse Trace
date: 2026-09-11
tags:

  - attack.privilege_escalation
  - attack.t1068
logsource:
    product: linux
    service: auditd
detection:
    selection_target:
        exe|endswith:

            - '/usr/lib/openssh/ssh-keysign'
            - '/usr/libexec/openssh/ssh-keysign'
            - '/usr/bin/chage'
    selection_parent_writable:
        parent_exe|startswith:

            - '/tmp/'
            - '/dev/shm/'
            - '/var/tmp/'
            - '/home/'
            - '/run/user/'
    filter_real_user:
        uid: 0
    condition: selection_target and selection_parent_writable and not filter_real_user
falsepositives:

    - Legitimate administrative chage usage from user directories (rare)
level: high

7. Sources

  • Elastic Security Labs, "Linux Detection Engineering — Local Privilege Escalation," https://www.elastic.co/security-labs/threat-command/linux-privilege-escalation-detection-framework, published 2026-09-11

8. Adverse Trace position

This is a high-value defensive publication, not an incident: no verified CVE reference data was resolved for this item, so Adverse Trace asserts no CVSS severity and no CISA-KEV exploitation state for any of the named CVEs, and no in-the-wild exploitation, ransomware, or actor attribution is claimed — none appears in the source. The material risk to EMEA financial services is structural: seven of 13 tracked 2026 Linux LPEs reuse one copy-on-write bug class across a dozen kernel interfaces, several are reachable from inside containers via user namespaces, and the descriptor-theft class (CVE-2026-46333) exfiltrates root-only material — SSH host keys, /etc/shadow — without ever producing a detectable root shell. Client impact concentrates on Linux server estates, container hosts, and any environment where an attacker can hold an unprivileged foothold; the SUID misconfiguration cases require no exploit at all. All technical detail is single-sourced to the Elastic publication and its referenced public PoCs — verify independently before enforcement actions. Adverse Trace will monitor for independent confirmation of the named CVEs, any emergence of CISA-KEV listings or in-the-wild exploitation reporting, and will update this advisory if verified reference data resolves.


Read the original source →

Published via PulseTrace — Adverse Trace threat intelligence.

Post this to LinkedIn
Formatting is converted automatically — headings, bullets, a link back & hashtags. Paste straight in.
J
Jeff Davies