Detection rules › Splunk

Linux Auditd Possible Setuid Execve Privesc

Status
production
Severity
low
Group by
host, ses
Author
Raven Tait, Nasreddine Bencherchali, Splunk
Source
github.com/splunk/security_content

The following detects privilege escalation via execve (syscall 59) where a process transitions from a non-root uid to euid=0 without a corresponding successful PAM authentication event (USER_AUTH, USER_ACCT, or CRED_ACQ) in the same audit session. Legitimate privilege elevation mechanisms such as sudo, su, and pkexec authenticate through PAM and generate these audit records tied to the session ID before granting elevated privileges. The absence of a matching successful PAM event alongside an effective UID change to root is anomalous and may indicate exploitation of a setuid binary, a kernel vulnerability, or another mechanism used to escalate privileges outside the normal authentication flow.

Known false positives

  • Processes with an unset audit session, such as cron jobs, that legitimately drop and reacquire root privileges outside of PAM, may trigger this detection and require filtering.

MITRE ATT&CK coverage

TacticTechniques
Privilege Escalation

Telemetry coverage

Rule body

name: Linux Auditd Possible Setuid Execve Privesc
id: e958e6ee-7c73-4eff-a4d9-43232d719b26
version: 1
creation_date: '2026-07-06'
modification_date: '2026-07-06'
author: Raven Tait, Nasreddine Bencherchali, Splunk
status: production
type: Anomaly
description: The following detects privilege escalation via execve (syscall 59) where a process transitions from a non-root uid to euid=0 without a corresponding successful PAM authentication event (USER_AUTH, USER_ACCT, or CRED_ACQ) in the same audit session. Legitimate privilege elevation mechanisms such as sudo, su, and pkexec authenticate through PAM and generate these audit records tied to the session ID before granting elevated privileges. The absence of a matching successful PAM event alongside an effective UID change to root is anomalous and may indicate exploitation of a setuid binary, a kernel vulnerability, or another mechanism used to escalate privileges outside the normal authentication flow.
data_source:
    - Linux Auditd Execve
search: >-
    `linux_auditd` (
    (type=SYSCALL syscall="59" uid!="0" euid="0")
    OR
    (type IN ("USER_AUTH","USER_ACCT","CRED_ACQ") res="success")
    )
    | eval is_suspicious_exec=if(type="SYSCALL" AND syscall="59" AND uid!="0" AND euid="0", 1, 0)
    | eval is_successful_auth=if(type IN ("USER_AUTH","USER_ACCT","CRED_ACQ") AND res="success", 1, 0)
    | stats
        count(eval(is_suspicious_exec=1)) as exec_count
        max(eval(if(is_suspicious_exec=1, _time, null()))) as lastTime
        max(is_successful_auth) as has_successful_auth
        min(eval(if(is_suspicious_exec=1, _time, null()))) as firstTime
        values(eval(if(is_suspicious_exec=1, comm, null()))) as process_name
        values(eval(if(is_suspicious_exec=1, euid, null()))) as euid
        values(eval(if(is_suspicious_exec=1, exe, null()))) as process_path
        values(eval(if(is_suspicious_exec=1, pid, null()))) as pid
        values(eval(if(is_suspicious_exec=1, ppid, null()))) as ppid
        values(eval(if(is_suspicious_exec=1, uid, null()))) as uid
        by host ses
    | where exec_count > 0 AND has_successful_auth != 1
    | rename host as dest, ses as session_id
    | `security_content_ctime(firstTime)`
    | `security_content_ctime(lastTime)`
    | `linux_auditd_possible_setuid_execve_privesc_filter`
how_to_implement: To implement this detection, the process begins by ingesting auditd data, that consist SYSCALL, TYPE, EXECVE and PROCTITLE events, which captures command-line executions and process details on Unix/Linux systems. These logs should be ingested and processed using Splunk Add-on for Unix and Linux (https://splunkbase.splunk.com/app/833), which is essential for correctly parsing and categorizing the data. The next step involves normalizing the field names  to match the field names set by the Splunk Common Information Model (CIM) to ensure consistency across different data sources and enhance the efficiency of data modeling. This approach enables effective monitoring and detection of linux endpoints where auditd is deployed.
known_false_positives: Processes with an unset audit session, such as cron jobs, that legitimately drop and reacquire root privileges outside of PAM, may trigger this detection and require filtering.
references:
    - https://github.com/sgkdev/packet_edit_meme
    - https://tuxcare.com/blog/pedit-cow-cve/
intermediate_findings:
    entities:
        - field: dest
          type: system
          score: 20
          message: $process_name$ was launched with euid 0 on [$dest$] without PAM auth.
threat_objects:
    - field: process_name
      type: process_name
analytic_story:
    - Linux Privilege Escalation
asset_type: Endpoint
cve:
    - CVE-2026-46331
mitre_attack_id:
    - T1068
product:
    - Splunk Enterprise
    - Splunk Enterprise Security
    - Splunk Cloud
category: endpoint
security_domain: endpoint

Stages and Predicates

Stage 1: search

`linux_auditd` ( (type=SYSCALL syscall="59" uid!="0" euid="0") OR (type IN ("USER_AUTH","USER_ACCT","CRED_ACQ") res="success") )

Stage 2: eval

| eval is_suspicious_exec=if(type="SYSCALL" AND syscall="59" AND uid!="0" AND euid="0", 1, 0)
is_suspicious_exec =
iftype = "SYSCALL" AND syscall = "59" AND uid != "0" AND euid = "0"1
else0

Stage 3: eval

| eval is_successful_auth=if(type IN ("USER_AUTH","USER_ACCT","CRED_ACQ") AND res="success", 1, 0)
is_successful_auth =
ifin(type, "USER_AUTH", "USER_ACCT", "CRED_ACQ") AND res = "success"1
else0

Stage 4: stats

| stats
    count(eval(is_suspicious_exec=1)) as exec_count
    max(eval(if(is_suspicious_exec=1, _time, null()))) as lastTime
    max(is_successful_auth) as has_successful_auth
    min(eval(if(is_suspicious_exec=1, _time, null()))) as firstTime
    values(eval(if(is_suspicious_exec=1, comm, null()))) as process_name
    values(eval(if(is_suspicious_exec=1, euid, null()))) as euid
    values(eval(if(is_suspicious_exec=1, exe, null()))) as process_path
    values(eval(if(is_suspicious_exec=1, pid, null()))) as pid
    values(eval(if(is_suspicious_exec=1, ppid, null()))) as ppid
    values(eval(if(is_suspicious_exec=1, uid, null()))) as uid
    by host ses

Stage 5: where

| where exec_count > 0 AND has_successful_auth != 1

Stage 6: rename

| rename host as dest, ses as session_id

Stage 7: search

| `security_content_ctime(firstTime)`

Stage 8: search

| `security_content_ctime(lastTime)`

Stage 9: search

| `linux_auditd_possible_setuid_execve_privesc_filter`

Indicators

These rows show field, operator, and value matches.