Fundamentals

T1059, T1546, T1548

Linux 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, sudo abuse, 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:

GroupRead (r)Write (w)Execute (x)
Owner (User)421
Group421
Others (World)421

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:

PermissionOctalWhat It MeansSecurity Risk
SUID4xxx (e.g., 4755)Runs with the file owner’s privileges, not the executor’spasswd, sudo, ping — but any unknown SUID binary is a privilege escalation vector (T1548.001)
SGID2xxx (e.g., 2770)Runs with the file group’s privilegesNew files inherit the group — directory-level SGID can expose sensitive data
Sticky Bit1xxx (e.g., 1777)Only the file owner can delete or rename their filesUsed 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

FilePurpose
/etc/pam.d/sshdSSH authentication rules
/etc/pam.d/sudosudo authentication rules
/etc/pam.d/loginConsole login rules
/etc/pam.d/common-authShared authentication rules (included by other configs)
/etc/pam.d/common-passwordPassword strength rules
/etc/security/Additional PAM module configs

PAM Control Values

ControlMeaningSecurity Implication
requiredMust succeed. If fails, other modules still run, but final result is failurePrevents against blanket failure
requisiteMust succeed. If fails, stops processing immediatelyFaster rejection — useful for MFA enforcement
sufficientIf succeeds and no prior required failures, authentication passesUsed for alternative auth methods (SSH keys + MFA)
optionalResult is ignored unless it’s the only moduleLogging-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 PatternWhat It MeansDetection Signal
Failed password for root from 10.0.0.5 port 22 ssh2Failed SSH login attemptBrute force — correlate with volume (10+/min)
Accepted password for jdoe from 192.168.1.10 port 22 ssh2Successful password-based SSH loginNormal — unless from an unusual source IP
Accepted publickey for jdoe from 192.168.1.10 port 22 ssh2Successful SSH key loginNormal — SSH keys are the recommended method
pam_unix(sshd:auth): authentication failurePAM auth failureCheck if preceded by successful auth (indicates password guessing)
sudo: jdoe : TTY=pts/0 ; PWD=/home/jdoe ; USER=root ; COMMAND=/bin/bashsudo command executionTrack every sudo escalation — unusual commands are high value
CRON[12345]: (root) CMD (/usr/bin/evil.sh)Cron job executed as rootMalware commonly persists via cron jobs (T1053.003)
User root not allowed because no TTYsudo attempted without a TTYMay indicate automated script or webshell
pam_tally2: Account blocked due to 10 failed loginsAccount locked due to brute forceEscalate — 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 RuleWhat It MonitorsWhy
-w /etc/passwd -p wa -k identityUser account changesTrack new users, UID changes
-w /etc/shadow -p wa -k identityPassword file changesTrack password hash modifications
-w /etc/sudoers -p wa -k sudoerssudoers file changesTrack privilege escalation configuration
-w /etc/ssh/sshd_config -p wa -k sshdSSH config changesTrack SSH hardening/degradation
-a always,exit -S execve -k processAll process executionCommand and scripting activity
-a always,exit -S connect -k networkOutbound network connectionsC2 and beacon detection
-a never,exit -F auid=1000 -k auditctl_skipSkip noise from normal adminExclude 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.

FeatureAppArmorSELinux
Configuration stylePath-based (profile per executable)Label-based (every file/process gets a context label)
Ease of useEasier — human-readable profilesSteeper learning curve
GranularityGood — path-levelFine — class/permission level
Default onUbuntu, Debian, OpenSUSERHEL, CentOS, Fedora
Failure modeComplain (log only) or EnforcePermissive (log only) or Enforcing
Typical statusaa-status or apparmor_statusgetenforce, 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

ArtifactPathWhat to Look For
SSH authorized_keys~/.ssh/authorized_keysUnexpected 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 . prefixRansom notes, scripts, downloaders
History files~/.bash_history, ~/.zsh_historyCommands the attacker ran
SUID binariesEntire filesystemBinaries changed to SUID root
Kernel modules/lib/modules/Rootkit .ko files
LD_PRELOAD/etc/ld.so.preload, env varsLibrary 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"

Sources