ExecutionNetworkAnti-forensics
/proc Live Artifacts: Processes, Sockets and Deleted Files
The /proc pseudo-filesystem on a live Linux host: process command lines, environments, open files, memory maps, sockets and deleted binaries.
- Location
- /proc/<pid>/
- Proves
- What is running right now, from which binary, with which arguments, files and network connections
- Timestamps
- No file timestamps of value; process start time in clock ticks since boot (/proc/<pid>/stat field 22)
- Access
- root to see every process's exe, environ, fd and maps; other users see only their own
- Retention
- Volatile: gone at process exit or reboot
- Collection
- UAC, Velociraptor, cp, AVML
Tools
Compare all tools- psCLI · built into Linux
- ssCLI · built into Linux
- lsofCLI · built into Linux
- VelociraptorPlatform · open source
- Volatility 3CLI · open source
What it is
/proc is a pseudo-filesystem generated by the kernel on demand. Nothing in it is stored on disk: every read asks the kernel for the current state of a process, a socket table or a kernel subsystem. On a live system it is the fastest way to see what is running, where each process came from and what it is talking to, and it survives some anti-forensic tricks that defeat disk analysis, such as a binary deleted after launch.
Because it is live state, /proc sits near the top of the order of volatility: collect it before anything that changes the system, and ideally alongside a memory image.
Where it lives
| Path | Content |
|---|---|
/proc/<pid>/exe | Symlink to the executable; readable (and copyable) even if the file was deleted |
/proc/<pid>/cmdline | Arguments, NUL-separated |
/proc/<pid>/environ | Initial environment, NUL-separated (root or same user) |
/proc/<pid>/cwd, /proc/<pid>/root | Current working directory and root directory (reveals chroot or container root) |
/proc/<pid>/fd/ | One symlink per open file descriptor: files, socket:[inode], pipe:[inode], anon_inode: |
/proc/<pid>/maps | Memory mappings with backing file path, flags (deleted) when the file is gone |
/proc/<pid>/status | Name, state, PPid, Uid/Gid (real, effective, saved, fs), capabilities |
/proc/<pid>/stat | Single-line process record; field 22 starttime |
/proc/<pid>/comm | Short name (16 bytes max), writable by the process itself |
/proc/net/tcp, tcp6, udp, udp6, unix | Socket tables with hex addresses and socket inode numbers |
/proc/modules | Loaded kernel modules (same data as lsmod) |
/proc/mounts | Current mounts of the reading process's mount namespace |
/proc/sys/kernel/tainted | Kernel taint flags |
Paths are identical across distributions. On systems mounted with hidepid= on /proc, non-root users cannot see other users' processes.
What it proves
- Which processes exist now, their parent-child tree, user and group IDs, and arguments.
- Which binary backs each process, even after deletion (
exe -> /path (deleted)), and allows recovering that binary. - Fileless execution:
exepointing to/memfd:<name> (deleted)shows a program run from an anonymous memory file created withmemfd_create. - Which files, sockets and pipes each process holds open; which remote addresses it is connected to (join
/proc/net/*inode numbers withfd/links). - Environment variables such as
LD_PRELOAD,HISTFILEor proxy settings passed to a process. - Not proven: anything about processes that already exited. A kernel rootkit can also filter what
/procshows, so compare with memory analysis.
Key fields
| Field | Where | Meaning |
|---|---|---|
PPid | status | Parent PID |
Uid, Gid | status | Real, effective, saved set and filesystem IDs |
CapEff | status | Effective capability mask |
starttime | stat field 22 | Start time in clock ticks after boot |
(deleted) suffix | exe, maps, fd/* links | Backing file was unlinked |
local_address, rem_address, st, uid, inode | /proc/net/tcp | Hex IP:port pairs, TCP state (0A = LISTEN, 01 = ESTABLISHED), owner UID, socket inode |
Timestamps
Files under /proc show the time the kernel created the inode for the reader, not the process start, so do not use ls -l times. Convert starttime instead: divide by the clock tick rate (getconf CLK_TCK, usually 100) and add it to the boot time (btime in /proc/stat, Unix seconds UTC).
pid=1234
st=$(awk '{print $22}' /proc/$pid/stat) # safe unless comm contains spaces
btime=$(awk '/^btime/{print $2}' /proc/stat)
date -u -d @$(( btime + st / $(getconf CLK_TCK) ))
ps -o lstart= -p <pid> gives the same value in local time.
Retention
None. Entries vanish when the process exits, and all of /proc is rebuilt at boot. Capture before containment actions such as killing processes, restarting services or isolating the network (which drops connections).
Collection
- UAC live-response artifacts record process listings,
/proc/<pid>links, open files and/proc/modules; itslive_response/process/deleted.yamlartifact copies the binary of any process whose executable shows as(deleted)(first 20 MB), plus deleted files those processes still hold open. - Velociraptor:
Linux.Sys.Pslist,Linux.Sys.Maps,Linux.Network.Netstatand friends over a fleet. - Manual, from trusted binaries:
# recover a deleted or memfd binary before the process ends
cp /proc/1234/exe /cases/host01/pid1234.bin && sha256sum /cases/host01/pid1234.bin
tr '\0' ' ' < /proc/1234/cmdline; echo
tr '\0' '\n' < /proc/1234/environ
ls -l /proc/1234/fd /proc/1234/cwd
ls -l /proc/[0-9]*/exe 2>/dev/null | grep -E '\(deleted\)|memfd:'
Take a memory image (see LiME and AVML) too: /proc answers "what now", memory lets you re-ask later.
Parsing
ps -eo pid,ppid,user,lstart,args --forest, ss -tanp, ss -xp and lsof -nP read /proc for you. For a memory image, Volatility 3 reconstructs the same view offline with linux.pslist, linux.pstree, linux.psaux, linux.envars, linux.lsof, linux.proc.Maps and linux.sockstat.
Investigator tips
- A process whose
exeis(deleted)ormemfd:is a priority finding: legitimate cases exist (package upgrades replacing a running binary) but check the package history first. commandargv[0]can be changed by the process; trustexeand the mapped files instead.- Processes with
cwdin /tmp, /var/tmp or /dev/shm deserve a look. - Compare the PID list from
/procwithpsoutput and with memory: a mismatch suggests userland hooking (ld.so.preload) or a kernel rootkit (kernel modules). - A different
rootlink than/indicates a chroot or a container; map it to the container ID before drawing conclusions (containers). - Record the clock: live collection times are only meaningful with the host's time and timezone captured at the same moment.