Skip to content

auditd EXECVE Forensics: auid, ses and Hex Arguments

Reconstruct command lines from Linux audit.log: grouping records by event, EXECVE argument reassembly, hex-encoded arguments, auid and ses across sudo.

Published on 4 min read

TL;DR. With an execve rule loaded, audit.log records every program run on the host. One execution is several records (SYSCALL, EXECVE, CWD, PATH, PROCTITLE) sharing the same msg=audit(sec.msec:serial) stamp. Group by that stamp, decode hex-encoded arguments, and use auid (the login user) and ses (the login session) to follow a user through sudo -i into a root shell, where auth.log goes blind.

Does the host even have it?

auditd is installed and enabled by default on RHEL and Fedora, not on Debian and Ubuntu. Even where it runs, no execve records exist unless a rule asks for them, for example:

-a always,exit -F arch=b64 -S execve -k exec

Read /etc/audit/rules.d/*.rules on the image (and the output of auditctl -l if collected live) before concluding anything from missing records. Without execve rules you still get the user-space events: USER_AUTH, USER_LOGIN, USER_START, USER_END, USER_CMD (sudo), USER_CHAUTHTOK (password change), ADD_USER, and audit configuration changes.

One event, several records

type=SYSCALL msg=audit(1789381120.086:181322): arch=c000003e syscall=59 success=yes exit=0 ppid=3200 pid=3204 auid=1001 uid=0 gid=0 euid=0 tty=pts1 ses=114 comm="tar" exe="/usr/bin/tar" key="exec"
type=EXECVE msg=audit(1789381120.086:181322): argc=4 a0="tar" a1="czf" a2="/tmp/.f.tgz" a3=2F7372762F66696E616E63652F513320636C6F7365
type=CWD msg=audit(1789381120.086:181322): cwd="/home/svc_backup"
type=PATH msg=audit(1789381120.086:181322): item=0 name="/usr/bin/tar" inode=13113204 ... nametype=NORMAL
type=PROCTITLE msg=audit(1789381120.086:181322): proctitle=74617200637A66002F746D702F2E662E74677A002F7372762F66696E616E63652F513320636C6F7365
type=EOE msg=audit(1789381120.086:181322):

All six lines are one event. The stamp 1789381120.086:181322 is epoch seconds (UTC), milliseconds, and a serial number generated by the kernel. The serial restarts at boot, so group by the whole stamp, not the serial alone. Records of different events can interleave in the file; grouping by stamp handles that.

Reassembling the command line

The EXECVE record holds argc and one field per argument:

  • Quoted values (a1="czf") are plain text.
  • Unquoted hex values (a3=2F7372...) are hex-encoded because the argument contains a space, a double quote, a control character or non-ASCII bytes. Decoding 2F7372762F66696E616E63652F513320636C6F7365 gives /srv/finance/Q3 close: one argument with a space, which the plain sudo line in auth.log cannot distinguish from two.
  • Long arguments are split: a1_len=N followed by a1[0]=..., a1[1]=... chunks, and a large command line may span several EXECVE records of the same event. Concatenate the chunks in order before decoding.
  • PROCTITLE holds the command line as the process saw it, hex-encoded with NUL separators, and truncated by the kernel for long command lines. Prefer EXECVE when both exist.

CWD gives the working directory, so relative paths in the arguments can be resolved. PATH records list the executable and the loader, with inode and owner.

auid and ses: following the user into root

The SYSCALL record carries two identities:

  • uid, euid: who the process runs as right now (0 inside a root shell).
  • auid: the audit login UID, set once when the user logs in (the LOGIN record: old-auid=4294967295 auid=1001) and inherited by every child process, including through sudo and su. 4294967295 means unset: daemons and boot-time processes.

And one session:

  • ses: the audit session ID, set at the same time. Every command of that login, as the user or as root, carries it.

In practice: auth.log shows svc_backup running sudo -i at 10:04, then nothing until the shell closes. audit.log for ses=114 shows what happened inside that shell:

type=SYSCALL ... auid=1001 uid=0 euid=0 tty=pts1 ses=114 comm="passwd" exe="/usr/bin/passwd"
type=SYSCALL ... auid=1001 uid=0 euid=0 tty=pts1 ses=114 comm="crontab" exe="/usr/bin/crontab" key="exec"
type=EXECVE  ... argc=4 a0="crontab" a1="-u" a2="svc_backup" a3="/tmp/.c"

uid=0 says root ran it; auid=1001 says it was svc_backup's login. The journal stores the same values as _AUDIT_LOGINUID and _AUDIT_SESSION, which lets you link journal entries to the audit session.

RAW and ENRICHED

With log_format = ENRICHED (the upstream default in current audit releases; distributions can override it), auditd appends resolved names after a 0x1D byte, in upper case: AUID="svc_backup" UID="root" SYSCALL=execve. These names were resolved on the original host, which makes them more reliable than ausearch -i run on an analysis workstation with a different /etc/passwd. With RAW, resolve UIDs with the image's own /etc/passwd.

ausearch for the classics

ausearch -if audit.log -m EXECVE -ul 1001 -i        # everything run under login UID 1001
ausearch -if audit.log --session 114 -i             # one login session
ausearch -if audit.log -m USER_CMD -i               # sudo commands, hex decoded
ausearch -if audit.log -m CONFIG_CHANGE,DAEMON_END -i   # audit tampering

-i interprets values using the analysis host's account files unless the log is ENRICHED.

What to look for

  • Reconnaissance right after login: id, uname, cat /etc/passwd, sudo -l.
  • Persistence: crontab, systemctl --user enable, writes under /etc/systemd/system or ~/.config/systemd/user.
  • Staging and exfiltration: tar, zip, rclone, curl, scp with paths to sensitive data.
  • Anti-forensics: rm of journal files, scripts run against /var/log/wtmp, ln -sf /dev/null ~/.bash_history, history -c (a builtin, so no execve record), auditctl -D or -e 0.
  • Reverse-shell-like command lines: interpreters or network tools whose arguments redirect a shell to a remote address. Treat a pattern match as a lead and read the full argument list.

In the browser

Linux Log Parser groups audit records by stamp, reassembles EXECVE arguments including hex and chunked ones, reads RAW and ENRICHED logs, uses ses to attach commands to rebuilt sessions, and flags persistence, log-clearing commands, suspicious tools and reverse-shell-like patterns. The walkthrough follows ses=114 end to end, and the auditd cheat sheet covers rules, retention and record types.

Related articles

A worked Linux log investigation on a synthetic jump host: SSH password guessing, a login from a new IP, sudo -i, cron and systemd persistence, log tampering.
How the four Linux log families fit together in an investigation, what each one proves, where they disagree, and how to merge them into one timeline.
Read /var/log/auth.log and /var/log/secure in an investigation: SSH brute force and logins, sudo and su root shells, password and account changes, time formats.