Fundamentals
T1059, T1546, T1548Linux Security Fundamentals
A comprehensive guide to Linux security for SOC analysts — file permissions, PAM, auth logs, auditd, AppArmor/SELinux, and Linux process forensics. Covers the essential Linux knowledge every analyst needs.
View on Graph
Why Linux Security Matters for SOC Analysts
- Most SOC analysts train on Windows first, but modern enterprise environments are Linux-heavy: cloud workloads, container hosts, CI/CD pipelines, web servers, and network appliances all run Linux.
- Linux breach investigations require understanding a different authentication model (PAM), different logging (syslog, auth.log, auditd), different access controls (DAC vs MAC), and different forensic artifacts.
- Attackers targeting Linux environments use techniques like SSH key theft,
sudoabuse, cron job persistence, kernel rootkits, and container escape — none of which have direct Windows equivalents. - This article covers the Linux security primitives every analyst needs to triage alerts, read logs, and investigate incidents on Linux systems.
File Permissions and ACLs — Linux DAC
Linux uses a three-tier permission model for every file and directory, plus optional Access Control Lists (ACLs) for finer-grained control.
Standard Unix Permissions
Every file has three permission groups, each with three bits:
| Group | Read (r) | Write (w) | Execute (x) |
|---|---|---|---|
| Owner (User) | 4 | 2 | 1 |
| Group | 4 | 2 | 1 |
| Others (World) | 4 | 2 | 1 |
Permissions are expressed as a 3-digit octal number: chmod 755 means owner=rwx (7), group=rx (5), others=rx (5).
Investigate permission abuse — SUID and SGID bits:
| Permission | Octal | What It Means | Security Risk |
|---|---|---|---|
| SUID | 4xxx (e.g., 4755) | Runs with the file owner’s privileges, not the executor’s | passwd, sudo, ping — but any unknown SUID binary is a privilege escalation vector (T1548.001) |
| SGID | 2xxx (e.g., 2770) | Runs with the file group’s privileges | New files inherit the group — directory-level SGID can expose sensitive data |
| Sticky Bit | 1xxx (e.g., 1777) | Only the file owner can delete or rename their files | Used on /tmp — prevents users from deleting each other’s temp files |
Detection — find all SUID binaries:
# List all SUID binaries (privilege escalation risk)
find / -perm -4000 -type f 2>/dev/null
# List all SGID binaries
find / -perm -2000 -type f 2>/dev/null
# Compare against a known-good baseline — any new SUID binary is suspicious
Access Control Lists (ACLs)
Standard Unix permissions only cover one user and one group. ACLs allow multiple users and groups with different permissions on a single file.
# View ACL on a file
getfacl /etc/shadow
# Set ACL — grant user 'jane' read access to a file
setfacl -m u:jane:r /var/log/syslog
# Remove ACL entry
setfacl -x u:jane /var/log/syslog
Detection — files with ACLs that grant unexpected access:
# Find files with ACL entries (beyond standard ugo/rwx)
find / -type f \( -perm -0001 -o -perm -0010 -o -perm -0100 \) -exec getfacl {} \; 2>/dev/null
PAM — Pluggable Authentication Modules
PAM (Pluggable Authentication Modules) controls how Linux systems authenticate users — password-based, SSH key, LDAP, RADIUS, MFA, and more.
PAM Configuration Files
| File | Purpose |
|---|---|
/etc/pam.d/sshd | SSH authentication rules |
/etc/pam.d/sudo | sudo authentication rules |
/etc/pam.d/login | Console login rules |
/etc/pam.d/common-auth | Shared authentication rules (included by other configs) |
/etc/pam.d/common-password | Password strength rules |
/etc/security/ | Additional PAM module configs |
PAM Control Values
| Control | Meaning | Security Implication |
|---|---|---|
required | Must succeed. If fails, other modules still run, but final result is failure | Prevents against blanket failure |
requisite | Must succeed. If fails, stops processing immediately | Faster rejection — useful for MFA enforcement |
sufficient | If succeeds and no prior required failures, authentication passes | Used for alternative auth methods (SSH keys + MFA) |
optional | Result is ignored unless it’s the only module | Logging-only modules, informational |
How to Check PAM Config for Backdoors
Attackers who gain root can modify PAM to: (1) allow any password for a specific user, (2) log plaintext passwords, (3) bypass MFA requirements.
Key checks:
# Check for unexpected PAM module inclusions
grep -r "pam_unix.so" /etc/pam.d/ -- look for nullok (allows empty passwords)
# Check if pam_tally2 (lockout) is disabled
grep -r "pam_tally2\|pam_faillock" /etc/pam.d/
# Check for custom/unexpected PAM modules
ls -la /lib/x86_64-linux-gnu/security/*.so | grep -vE 'pam_(unix|ldap|sss|tally|cracklib|wheel|loginuid|env|limit)'
Linux Auth Logs — /var/log/auth.log
/var/log/auth.log (Debian/Ubuntu) or /var/log/secure (RHEL/CentOS) is the single most important log for Linux authentication events.
Key Auth Log Patterns
| Log Pattern | What It Means | Detection Signal |
|---|---|---|
Failed password for root from 10.0.0.5 port 22 ssh2 | Failed SSH login attempt | Brute force — correlate with volume (10+/min) |
Accepted password for jdoe from 192.168.1.10 port 22 ssh2 | Successful password-based SSH login | Normal — unless from an unusual source IP |
Accepted publickey for jdoe from 192.168.1.10 port 22 ssh2 | Successful SSH key login | Normal — SSH keys are the recommended method |
pam_unix(sshd:auth): authentication failure | PAM auth failure | Check if preceded by successful auth (indicates password guessing) |
sudo: jdoe : TTY=pts/0 ; PWD=/home/jdoe ; USER=root ; COMMAND=/bin/bash | sudo command execution | Track every sudo escalation — unusual commands are high value |
CRON[12345]: (root) CMD (/usr/bin/evil.sh) | Cron job executed as root | Malware commonly persists via cron jobs (T1053.003) |
User root not allowed because no TTY | sudo attempted without a TTY | May indicate automated script or webshell |
pam_tally2: Account blocked due to 10 failed logins | Account locked due to brute force | Escalate — password spray or brute force targeting this account |
Detection — SPL query for failed SSH logins:
index=linux sourcetype="auth.log" "Failed password"
| rex field=_raw "Failed password for (?<user>\S+) from (?<src_ip>\S+) port (?<port>\d+)"
| stats count by src_ip, user
| where count > 10
| sort - count
| eval alert = "SSH brute force — " . count . " attempts from " . src_ip . " targeting " . user
| table _time, src_ip, user, count, alert
Detection — SPL query for new SSH key additions:
index=linux sourcetype="auth.log" "New SSH key" OR "authorized_keys"
| table _time, user, file, _raw
| eval alert = "New SSH key added to authorized_keys — possible persistence"
auditd — Linux Audit System
auditd is the Linux equivalent of Windows Advanced Audit Policy — it watches file access, system calls, user/group changes, and network configuration changes.
Key Audit Rules Every SOC Should Have
| Audit Rule | What It Monitors | Why |
|---|---|---|
-w /etc/passwd -p wa -k identity | User account changes | Track new users, UID changes |
-w /etc/shadow -p wa -k identity | Password file changes | Track password hash modifications |
-w /etc/sudoers -p wa -k sudoers | sudoers file changes | Track privilege escalation configuration |
-w /etc/ssh/sshd_config -p wa -k sshd | SSH config changes | Track SSH hardening/degradation |
-a always,exit -S execve -k process | All process execution | Command and scripting activity |
-a always,exit -S connect -k network | Outbound network connections | C2 and beacon detection |
-a never,exit -F auid=1000 -k auditctl_skip | Skip noise from normal admin | Exclude normal admin activity from the noise bucket |
How to Check auditd Status
# Check if auditd is running
systemctl status auditd
# View current audit rules
auditctl -l
# Search audit logs for a specific user action
ausearch -ua jdoe -ts today
# Generate a report of failed syscalls
aureport -au -i --failed
AppArmor vs SELinux — Linux MAC
Mandatory Access Control (MAC) restricts what processes can do even when running as root. AppArmor and SELinux are the two major MAC implementations.
| Feature | AppArmor | SELinux |
|---|---|---|
| Configuration style | Path-based (profile per executable) | Label-based (every file/process gets a context label) |
| Ease of use | Easier — human-readable profiles | Steeper learning curve |
| Granularity | Good — path-level | Fine — class/permission level |
| Default on | Ubuntu, Debian, OpenSUSE | RHEL, CentOS, Fedora |
| Failure mode | Complain (log only) or Enforce | Permissive (log only) or Enforcing |
| Typical status | aa-status or apparmor_status | getenforce, sestatus |
Key Commands for Analysts
AppArmor:
# Check if AppArmor is enforcing
sudo aa-status
# View a profile (e.g., `nginx`)
cat /etc/apparmor.d/usr.sbin.nginx
# Set a profile to complain mode (log only, no blocking)
sudo aa-complain /usr/sbin/nginx
# Check for AppArmor denials
grep "DENIED" /var/log/syslog | grep apparmor
SELinux:
# Check current SELinux mode
getenforce
# View SELinux context of a file
ls -Z /etc/shadow
# View SELinux context of a running process
ps -eZ | grep nginx
# Check for SELinux denials
ausearch -m avc -ts recent
sealert -a /var/log/audit/audit.log
Detection — MAC bypass or disablement is a critical signal:
# SPL — detect SELinux disabled or set to permissive
index=linux sourcetype=audit.log "SELinux" "permissive" OR "disabled"
| eval alert = "CRITICAL — SELinux mode changed to permissive or disabled"
| table _time, host, _raw
Linux Process Forensics
When investigating a compromised Linux host, these are the artifacts every analyst collects:
Volatile Data Collection
# Running processes with network connections
netstat -tunap
# Process tree (PPID relationships)
ps auxf
# Open file handles per process
lsof -i -P -n
# Loaded kernel modules
lsmod
# ARP cache
arp -a
# Cron jobs (common persistence)
crontab -l
ls -la /etc/cron* /var/spool/cron/
# Systemd services (modern persistence)
systemctl list-units --type=service --state=running
Persistent Artifacts
| Artifact | Path | What to Look For |
|---|---|---|
| SSH authorized_keys | ~/.ssh/authorized_keys | Unexpected keys — attacker persistence |
| Cron jobs | /etc/crontab, /etc/cron.d/, /var/spool/cron/crontabs/ | Backdoor execution, reverse shell |
| Systemd services | /etc/systemd/system/ | Malicious service definitions |
| Hidden files | / and /tmp with . prefix | Ransom notes, scripts, downloaders |
| History files | ~/.bash_history, ~/.zsh_history | Commands the attacker ran |
| SUID binaries | Entire filesystem | Binaries changed to SUID root |
| Kernel modules | /lib/modules/ | Rootkit .ko files |
| LD_PRELOAD | /etc/ld.so.preload, env vars | Library injection rootkits |
Detection — Linux Persistence Scan
# Find recently modified cron files
find /etc/cron* /var/spool/cron -type f -mtime -7
# Find recently created systemd services
find /etc/systemd/system -name '*.service' -mtime -7
# Check for LD_PRELOAD rootkits
cat /etc/ld.so.preload 2>/dev/null || echo "No ld.so.preload — clean"
Related
- Privilege Escalation Investigation — detection and response for T1068 techniques
- Cloud Security Fundamentals — detection and response for T1525 techniques
- Elastic Security — detection and response for T1654 techniques
- Malware Analysis Fundamentals — detection and response for T1204 techniques
