contentintech
Learn/cybersecurity/Linux Security
Intermediate~22 min read

Linux Security

Linux permissions, users and privileges, hardening, SSH, SELinux/AppArmor, logging, and detecting privilege escalation.

PermissionsHardeningSELinuxAuditing

Linux Security Fundamentals

Linux powers most servers, containers, and cloud workloads, so securing it is a core defensive skill. This guide focuses on hardening: understanding the permission model, locking down remote access, enforcing mandatory access control, and detecting the signs of privilege escalation. Everything here should be practiced on systems you own, such as a local VM or a home lab.

The Permission Model

Every file has an owner, a group, and three permission triads: user, group, and other. Each triad has read (r=4), write (w=2), and execute (x=1) bits, combined into an octal value.

Octal Symbolic Meaning
644rw-r--r--Owner writes, all read
600rw-------Private (keys, secrets)
755rwxr-xr-xExecutable/dir, all traverse
700rwx------Owner-only directory
# Set permissions and ownership
chmod 600 ~/.ssh/id_ed25519       # private key: owner read/write only
chmod 755 /usr/local/bin/tool     # executable, world-readable
chown alice:developers report.txt # change owner and group
chmod u+x,g-w,o= script.sh        # symbolic: add exec, drop group write, clear other

Never 777

A chmod 777 makes a file world-writable, letting any user or compromised process modify it. If you think you need it, you almost certainly need correct ownership instead.

Users, Groups, and sudo

Users are defined in /etc/passwd, password hashes in /etc/shadow, and groups in /etc/group. sudo grants controlled privilege escalation, logged and configured in /etc/sudoers. Grant the narrowest command set, not blanket root.

# Edit sudoers safely (validates syntax on save)
visudo

# Least-privilege sudo entry: allow only service restarts
alice ALL=(root) /usr/bin/systemctl restart nginx

# Review who can do what
sudo -l -U alice

SUID, SGID, and the Sticky Bit

The SUID bit makes an executable run as its owner (often root) regardless of who launches it. This is why passwd can update /etc/shadow. But SUID is a classic privilege-escalation vector: a misconfigured or vulnerable SUID binary can hand an attacker root. SGID applies the same idea to groups, and the sticky bit on a directory (like /tmp) stops users deleting each other's files.

# Audit all SUID binaries on the system
find / -perm -4000 -type f 2>/dev/null

# Find SGID binaries
find / -perm -2000 -type f 2>/dev/null

# Remove SUID from a binary that does not need it
chmod u-s /path/to/binary

Baseline your SUID set

Record the expected SUID binaries on a clean system. Any new SUID binary appearing later is a strong indicator of tampering. Cross-reference unfamiliar entries against the GTFOBins project to understand escalation risk.

SSH Hardening

SSH is the primary remote-access surface. Prefer key-based authentication (Ed25519), disable password login and direct root login, and limit who may connect.

# /etc/ssh/sshd_config  (hardened)
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
AllowUsers alice bob
MaxAuthTries 3
LoginGraceTime 20
X11Forwarding no
ClientAliveInterval 300
ClientAliveCountMax 2

# Generate a modern key and reload the daemon
ssh-keygen -t ed25519 -a 100 -C "alice@laptop"
sudo systemctl reload ssh

Host Firewall with ufw

ufw is a friendly front end to nftables. Default to deny inbound, allow outbound, then open only required ports.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw limit 22/tcp        # rate-limit SSH against brute force
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Mandatory Access Control: SELinux vs AppArmor

Standard permissions are discretionary. MAC systems enforce policy the user cannot override, confining processes to only what they need even if compromised.

SELinux AppArmor
ModelLabel-basedPath-based
Default onRHEL/FedoraUbuntu/SUSE
Modesenforcing/permissive/disabledenforce/complain
# SELinux: check and set enforcing
getenforce
sudo setenforce 1                 # enforcing until reboot
# persist in /etc/selinux/config: SELINUX=enforcing

# AppArmor: check status and enforce a profile
sudo aa-status
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx

Auditing and Logging

auditd records security-relevant events; journald aggregates systemd logs. Ship logs off-host so an attacker cannot erase their tracks.

Path Contents
/var/log/auth.logAuth, sudo, SSH (Debian/Ubuntu)
/var/log/secureAuth events (RHEL)
/var/log/syslogGeneral system messages
/var/log/audit/audit.logauditd records
# Failed SSH logins
sudo grep "Failed password" /var/log/auth.log
sudo journalctl -u ssh --since "1 hour ago"

# Watch a sensitive file with auditd
sudo auditctl -w /etc/passwd -p wa -k passwd_changes
sudo ausearch -k passwd_changes

Detecting Privilege Escalation

Attackers who gain a foothold hunt for a path to root. Regularly review the classic vectors: unexpected SUID binaries, world-writable files in PATH, writable cron jobs, and overly broad sudoers rules.

# Review scheduled tasks
cat /etc/crontab; ls -la /etc/cron.*
# World-writable files (dangerous if in a privileged path)
find / -xdev -type f -perm -0002 2>/dev/null
# Capabilities that grant elevated powers
getcap -r / 2>/dev/null

File Integrity Monitoring

AIDE (Advanced Intrusion Detection Environment) builds a database of file hashes and attributes, then reports any change. Store the baseline database on read-only or off-host media so it cannot be silently rewritten.

sudo aideinit                       # build baseline
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
sudo aide --check                   # compare current state to baseline

Least Privilege

The unifying principle: every user, process, and service should have only the access it needs and nothing more. Run services as dedicated non-root accounts, drop Linux capabilities you do not use, isolate workloads with containers or namespaces, and remove packages you do not run. A smaller footprint means fewer things to patch and fewer paths to abuse.

Practice Exercises

  1. On a Linux VM, audit permissions in a web root: find any world-writable files with find . -perm -0002 and correct ownership and modes to least privilege.
  2. Harden sshd on the VM: switch to Ed25519 key auth, set PermitRootLogin no and PasswordAuthentication no, reload, and confirm password login is refused.
  3. Enable ufw with default-deny inbound, allow only SSH (rate-limited) and your app port, and verify with ufw status verbose.
  4. Set SELinux to enforcing (or put an AppArmor profile into enforce mode) and confirm services still start; investigate and resolve any denials in the audit log.
  5. Enumerate all SUID binaries with find / -perm -4000 -type f, compare against a documented baseline, and note any you cannot account for.
  6. Review /var/log/auth.log (or journalctl -u ssh) for failed login attempts, then practice this against an intentionally vulnerable box like DVWA or a TryHackMe/HackTheBox Linux room.

Section navigation