# Hardening Linux Systems

> Chapter 156 of the Courseiva SECURITY-PLUS curriculum — https://courseiva.com/learn/security-plus/hardening-linux

**Official objective:** 4.1 — Security Operations

## Introduction

Hardening Linux systems equips Security+ candidates and IT professionals with a critical skill. Properly securing Linux servers reduces the attack surface and prevents common exploits. This content maps directly to SY0-701 Objective 4.1 (Security Operations) and is essential for understanding host security controls. You will learn the specific commands, configuration files, and best practices tested on the exam.

## Hardening a Linux Server Like a Fortress

A king's treasure is safeguarded within a fortress. The fortress has multiple layers of defense: a moat, a drawbridge, arrow slits, and a keep with a locked door. Hardening a Linux system is like reinforcing each layer. The moat represents the firewall—cutting off access unless necessary. The drawbridge is the SSH service—only lower it for trusted visitors (key-based authentication) and keep it raised for everyone else (disable password auth). Arrow slits are file permissions—allow only specific archers (users) to shoot (read/write/execute) through certain windows. The keep door is the root account—lock it with a strong password and only allow entry via sudo (like a guard who checks IDs). The treasure itself is the data—encrypt it with LUKS or eCryptfs, like placing it in a locked chest. An attacker, like a thief, will probe the moat (port scan), try to force the drawbridge (brute-force SSH), or find a weak arrow slit (world-writable file). Hardening removes these vulnerabilities: disable unused services (seal unnecessary doors), apply patches (fix cracks in walls), and enable SELinux or AppArmor (add a magical barrier that blocks even if the thief gets inside).

## Core explanation

### What is Linux Hardening?
Linux hardening is the process of securing a Linux system by reducing its vulnerability surface. The goal is to minimize the number of potential entry points an attacker can exploit. This includes disabling unnecessary services, enforcing strong authentication, applying file permissions, and using kernel-level security modules. The SY0-701 exam expects you to know specific hardening techniques and their implementation commands.

### The Principle of Least Privilege
At the core of hardening is the principle of least privilege: every user, process, and service should have only the minimum permissions necessary to function. On Linux, this is enforced through user accounts, group memberships, and file permissions. The root account should never be used for daily tasks; instead, use `sudo` to grant specific privileges. Commands like `visudo` edit the `/etc/sudoers` file to control sudo access. For example:

```
%admin ALL=(ALL) ALL
```
This gives all members of the admin group full sudo access. For granular control, restrict commands:

```
username ALL=(ALL) /usr/bin/apt update, /usr/bin/apt upgrade
```

### Removing Unnecessary Services
Every listening service is a potential attack vector. Use `ss -tlnp` or `netstat -tulpn` to list open ports and associated services. Disable and remove services not required. For example, if a system does not need a web server, remove Apache or Nginx:

```
systemctl stop apache2
systemctl disable apache2
apt remove apache2
```

Common services to disable on a hardened server: `cups` (printing), `avahi-daemon` (mDNS), `bluetooth`, `rpcbind`, `telnet`, `ftp`. The exam often tests knowledge of `systemctl` commands to manage services.

### SSH Hardening
SSH is a primary attack target. Secure it by editing `/etc/ssh/sshd_config`:
- Disable root login: `PermitRootLogin no`
- Use key-based authentication: `PasswordAuthentication no`
- Change default port (optional): `Port 2222`
- Limit users: `AllowUsers alice bob`
- Use Protocol 2 only: `Protocol 2`

After changes, restart SSH: `systemctl restart sshd`. The exam may ask which configuration setting prevents brute-force attacks—answer: disabling password authentication or using key-based authentication.

### File Permissions and Ownership
Linux uses a permission model: read (r=4), write (w=2), execute (x=1) for owner, group, and others. Use `chmod` and `chown` to set proper permissions. For example, sensitive configuration files should be readable only by root:

```
chmod 600 /etc/shadow
chown root:root /etc/shadow
```

Special permissions: SUID (4000), SGID (2000), sticky bit (1000). SUID allows a program to run with the file owner's privileges—a common vulnerability if misapplied. Find all SUID files with:

```
find / -perm -4000
```

The exam expects you to know that the sticky bit on `/tmp` prevents users from deleting each other's files.

### Using sudo Instead of Root
Never log in as root. Use `sudo` for administrative tasks. Configure sudo via `/etc/sudoers`. A common hardening step is to require a password for sudo and log all commands:

```
Defaults logfile=/var/log/sudo.log
Defaults timestamp_timeout=5
```

The `timestamp_timeout` sets how long sudo credentials are cached (default 5 minutes). The exam may ask how to prevent sudo from caching credentials—set `timestamp_timeout` to 0.

### Kernel Hardening with sysctl
Kernel parameters can be tuned via `/etc/sysctl.conf` or files in `/etc/sysctl.d/`. Important parameters for security:
- `net.ipv4.ip_forward=0` (disable IP forwarding)
- `net.ipv4.conf.all.rp_filter=1` (enable reverse path filtering)
- `net.ipv4.tcp_syncookies=1` (enable SYN cookies)
- `kernel.exec-shield=1` (enable execution protection)
- `kernel.randomize_va_space=2` (enable ASLR)

Apply changes with `sysctl -p`. The exam may test knowledge of ASLR (Address Space Layout Randomization) as a defense against buffer overflow attacks.

### Mandatory Access Control with SELinux and AppArmor
SELinux (Security-Enhanced Linux) and AppArmor provide mandatory access control (MAC) beyond standard discretionary access control (DAC). SELinux uses labels and policies. Check status:

```
getenforce
sestatus
```

Set enforcing mode: `setenforce 1`. SELinux contexts can be viewed with `ls -Z`. Common commands:
- `chcon -t httpd_sys_content_t /var/www/html/index.html`
- `restorecon -Rv /var/www/html`

AppArmor uses profiles in `/etc/apparmor.d/`. Check status: `aa-status`. The exam expects you to know that SELinux and AppArmor are kernel modules that enforce security policies, and that SELinux is more common on Red Hat-based distributions, AppArmor on Debian/Ubuntu.

### Patching and Updates
Regular updates close known vulnerabilities. Use `apt update && apt upgrade` (Debian/Ubuntu) or `yum update` (RHEL/CentOS). Enable automatic security updates:

```
apt install unattended-upgrades
dpkg-reconfigure --priority=low unattended-upgrades
```

The exam may ask about patch management strategies—apply security patches promptly after testing in a non-production environment.

### Logging and Auditing
Centralized logging helps detect intrusions. Use `rsyslog` or `syslog-ng`. Configure `/etc/rsyslog.conf` to send logs to a remote server. Auditd monitors system calls:

```
auditctl -w /etc/passwd -p wa -k passwd_changes
aureport -k passwd_changes
```

The exam expects you to know that auditd logs can be reviewed with `ausearch` and `aureport`.

### Firewall Configuration
Use `iptables` or `nftables` (modern) or frontends like `ufw` (Ubuntu) and `firewalld` (RHEL). Default deny policy is best:

```
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw enable
```

Or with iptables:

```
iptables -P INPUT DROP
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -j DROP
```

The exam may test that a stateful firewall tracks connection states.

### Physical Security and Boot Loader
Physical access can bypass OS security. Set a GRUB password to prevent boot parameter changes. Encrypt the entire disk with LUKS during installation. The exam may ask about full disk encryption as a protection against data theft if the drive is removed.

### Summary of Commands and Files
Key files: `/etc/ssh/sshd_config`, `/etc/sudoers`, `/etc/sysctl.conf`, `/etc/apt/sources.list`, `/etc/rsyslog.conf`, `/etc/audit/auditd.conf`. Key commands: `systemctl`, `ss`, `chmod`, `chown`, `find`, `sudo`, `sysctl`, `getenforce`, `setenforce`, `ufw`, `iptables`, `auditctl`, `ausearch`.

## Real-world context

**Scenario 1: SOC Analyst Investigating a Compromised Linux Web Server**
A SOC analyst receives an alert from an IDS indicating outbound traffic from a Linux web server to a known malicious IP. The analyst checks the server's running services using `systemctl list-units --type=service --state=running` and finds an unknown service named 'systemd-helper' listening on port 4444. The analyst then reviews `/var/log/auth.log` and sees multiple failed SSH attempts from a foreign IP, followed by a successful login from an internal IP that should not have SSH access. The analyst uses `ausearch -m USER_LOGIN -sv yes` to find successful logins. The root cause: SSH was configured with password authentication enabled and root login permitted. The analyst immediately disables root login and password auth, changes all passwords, and removes the backdoor service. A common mistake is to focus only on the backdoor and not address the weak SSH configuration that allowed initial access.

**Scenario 2: System Administrator Hardening a New Linux Deployment**
An organization is deploying 50 Linux servers for a new application. The system administrator follows a hardening checklist. First, they create a baseline image with minimal services. They use `ss -tlnp` to verify only SSH and the application port are listening. They configure `/etc/ssh/sshd_config` with key-only authentication and disable root login. They set up `ufw` with default deny incoming and allow only necessary ports. They enable automatic security updates via `unattended-upgrades`. They also configure `auditd` to monitor `/etc/passwd` and `/etc/shadow`. They test the configuration by running a vulnerability scanner (e.g., OpenVAS) and address any findings. A common mistake is to forget to apply the same hardening to all servers consistently, leaving some servers vulnerable. Automation tools like Ansible or Puppet can enforce consistency.

**Scenario 3: Incident Response to a Privilege Escalation via SUID Binary**
An attacker gains initial access through a vulnerable web application. They run `find / -perm -4000` and discover a custom SUID binary owned by root that allows execution of arbitrary commands. The attacker exploits it to gain a root shell. The incident responder reviews `auditd` logs to see the SUID binary execution. The responder then removes the SUID bit from the binary: `chmod u-s /path/to/binary`. They also check for other SUID binaries using the find command and remove unnecessary ones. The root cause: the binary was installed with SUID during development and never hardened. A common mistake is to only patch the web application vulnerability and not check for SUID binaries, leaving the privilege escalation vector open.

## Exam focus

**What SY0-701 Tests on Linux Hardening**
Objective 4.1 covers implementing host security solutions. For Linux, the exam focuses on: (1) Disabling unnecessary services and ports, (2) SSH key-based authentication and configuration, (3) File permissions and the principle of least privilege, (4) Using sudo instead of root, (5) Kernel hardening with sysctl (especially ASLR and SYN cookies), (6) SELinux and AppArmor basics, (7) Patch management, (8) Logging and auditing with auditd. The exam will present scenario-based questions where you must choose the correct command or configuration.

**Common Wrong Answers and Why**
1. **'Disable SSH completely'** – While secure, it's impractical for remote administration. The correct answer is to harden SSH, not disable it.
2. **'Use chmod 777 for configuration files'** – This gives everyone full access, violating least privilege. The correct permission is 600 or 644.
3. **'Set SELinux to disabled'** – Many candidates think disabling SELinux improves performance, but the exam expects you to set it to enforcing mode and configure policies.
4. **'Change root password daily'** – The correct approach is to disable root login and use sudo.

**Specific Terms and Acronyms**
- **ASLR** (Address Space Layout Randomization) – `kernel.randomize_va_space=2`
- **SELinux** – `setenforce 1`, `getenforce`, `sestatus`
- **AppArmor** – `aa-status`, `aa-enforce`
- **SUID** – `find / -perm -4000`
- **Sticky bit** – `/tmp` directory
- **sysctl** – `/etc/sysctl.conf`
- **auditd** – `auditctl`, `ausearch`, `aureport`

**Common Trick Questions**
- Question asks for 'best way to prevent brute-force SSH attacks' – Answer is 'Disable password authentication' or 'Use key-based authentication', not 'Change SSH port' (security by obscurity).
- Question asks for 'kernel-level protection against buffer overflows' – Answer is 'ASLR' (or 'kernel.randomize_va_space=2'), not 'SELinux'.
- Question asks for 'mandatory access control' – Answer is 'SELinux' or 'AppArmor', not 'sudo' or 'chmod'.

**Decision Rule for Eliminating Answers**
On scenario questions, first identify the threat: (1) Unauthorized access? → SSH hardening, disable root, use keys. (2) Privilege escalation? → Check SUID, set proper permissions. (3) Network-based attacks? → Firewall, disable services. (4) Data theft? → Encryption, file permissions. Eliminate answers that conflict with the principle of least privilege or that disable functionality entirely without alternative controls.

## Step by step

1. **Inventory Running Services** — Use `systemctl list-units --type=service --state=running` to list all active services. Cross-reference with `ss -tlnp` to see listening ports. Identify services that are not required for the server's role (e.g., cups, bluetooth, avahi-daemon). Document each service and its necessity. Logs from `journalctl -u <service>` can show if the service is actively used. This step establishes the baseline attack surface.
2. **Disable and Remove Unnecessary Services** — For each unnecessary service, stop it immediately: `systemctl stop <service>`. Then disable it to prevent startup on boot: `systemctl disable <service>`. Optionally remove the package: `apt remove <package>` or `yum remove <package>`. Verify with `systemctl list-units --type=service --state=running` again. Common mistakes: forgetting to disable after stopping, or removing a package that other services depend on. Use `apt autoremove` to clean orphaned packages.
3. **Harden SSH Configuration** — Edit `/etc/ssh/sshd_config`. Set `PermitRootLogin no`, `PasswordAuthentication no` (after key setup), `Protocol 2`, and `MaxAuthTries 3`. Optionally change port and restrict users. Generate SSH keys with `ssh-keygen -t ed25519` and deploy public keys. Test configuration with `sshd -t` before restarting. Reload: `systemctl reload sshd`. Monitor `/var/log/auth.log` for failed attempts. Common mistake: locking yourself out—always keep a root session open while testing.
4. **Apply File Permissions and Ownership** — Review critical files: `/etc/passwd`, `/etc/shadow`, `/etc/ssh/sshd_config`, `/etc/sudoers`. Set permissions: `chmod 644 /etc/passwd`, `chmod 600 /etc/shadow`, `chmod 600 /etc/ssh/sshd_config`. Use `find / -perm -4000` to locate SUID binaries and remove SUID from unnecessary ones (e.g., `chmod u-s /usr/bin/wall`). Set sticky bit on `/tmp` if not set: `chmod +t /tmp`. Verify with `ls -ld /tmp`. Common mistake: setting permissions too permissive (e.g., 777 on config files).
5. **Configure Kernel Parameters and Enable MAC** — Edit `/etc/sysctl.conf` or create a file in `/etc/sysctl.d/`. Add `net.ipv4.ip_forward=0`, `net.ipv4.tcp_syncookies=1`, `kernel.randomize_va_space=2`. Apply with `sysctl -p`. For MAC, ensure SELinux or AppArmor is installed and in enforcing mode. For SELinux: `setenforce 1` and edit `/etc/selinux/config` to set `SELINUX=enforcing`. For AppArmor: `aa-enforce /path/to/profile`. Verify with `getenforce` or `aa-status`. Common mistake: disabling SELinux instead of configuring it correctly.
6. **Enable Logging and Audit** — Configure `rsyslog` to forward logs to a remote server if possible. Edit `/etc/rsyslog.conf` and add `*.* @logserver:514`. Restart rsyslog. Install and configure auditd: `auditctl -w /etc/shadow -p wa -k shadow_changes`. Set audit rules in `/etc/audit/rules.d/`. Ensure auditd starts on boot: `systemctl enable auditd`. Test with `ausearch -k shadow_changes`. Common mistake: not setting sufficient disk space for logs, causing log rotation issues.

## Comparisons

### SELinux vs AppArmor

**SELinux:**
- Uses labels (contexts) for files, processes, and ports
- Supports multi-level security (MLS) and multi-category security (MCS)
- More complex to configure but more granular
- Commonly used on Red Hat, CentOS, Fedora
- Policies are written in a custom language

**AppArmor:**
- Uses path-based profiles (e.g., /usr/bin/foo)
- Does not support MLS/MCS natively
- Easier to configure with learning mode
- Commonly used on Debian, Ubuntu, SUSE
- Policies are written in a simpler syntax

### iptables vs ufw

**iptables:**
- Low-level packet filtering framework
- Requires manual chain and rule management
- More flexible but steeper learning curve
- Works on all Linux distributions
- Persistence requires separate tools (iptables-save/restore)

**ufw:**
- Frontend to iptables/nftables
- Simple syntax: allow/deny/reject
- Less flexible but easier for basic rules
- Pre-installed on Ubuntu, available on others
- Persistence built-in via /etc/ufw/

## Common misconceptions

- **Misconception:** Setting a complex root password is sufficient to secure a Linux server. **Reality:** Even a strong root password can be brute-forced if SSH password authentication is enabled. The correct approach is to disable root login entirely and use sudo with key-based authentication.
- **Misconception:** Disabling SELinux improves security because it reduces complexity. **Reality:** SELinux adds an extra layer of mandatory access control. Disabling it removes protection against compromised processes. The correct approach is to configure SELinux in enforcing mode with proper policies.
- **Misconception:** Changing the default SSH port to a high number (e.g., 2222) effectively prevents attacks. **Reality:** Changing the port is security by obscurity and does not stop determined attackers who can scan all ports. The correct hardening includes disabling password authentication and using keys.
- **Misconception:** Once a service is disabled with `systemctl disable`, it is completely removed from the system. **Reality:** `systemctl disable` only prevents the service from starting at boot; the service can still be started manually. To fully remove, use `systemctl stop` and optionally remove the package.
- **Misconception:** File permissions like 777 are acceptable for temporary files in /tmp. **Reality:** The sticky bit on /tmp prevents users from deleting others' files, but 777 permissions allow any user to read or modify them. Sensitive data in /tmp should be protected with proper permissions or encryption.

## Key takeaways

- Disable root login via SSH: set `PermitRootLogin no` in `/etc/ssh/sshd_config`.
- Use key-based SSH authentication; disable password authentication with `PasswordAuthentication no`.
- Apply the principle of least privilege: use `sudo` instead of root; restrict sudo commands in `/etc/sudoers`.
- Remove unnecessary services: `systemctl stop <service> && systemctl disable <service>`.
- Set file permissions: `chmod 600` for sensitive files like `/etc/shadow`.
- Enable ASLR: set `kernel.randomize_va_space=2` in `/etc/sysctl.conf`.
- Use SELinux or AppArmor in enforcing mode to enforce mandatory access control.
- Regularly apply security patches; use `unattended-upgrades` for automatic updates.
- Configure auditd to monitor critical files: `auditctl -w /etc/passwd -p wa -k passwd_changes`.
- Use a firewall (ufw, firewalld, iptables) with default deny incoming policy.

## FAQ

**What is the best way to prevent SSH brute-force attacks on Linux?**

The best way is to disable password authentication and use SSH key-based authentication exclusively. Set `PasswordAuthentication no` in `/etc/ssh/sshd_config`. Additionally, disable root login (`PermitRootLogin no`) and consider using `fail2ban` to temporarily ban IPs with multiple failed attempts. Changing the SSH port is not effective as a primary defense.

**How do I check if SELinux is enabled and enforcing?**

Use the `getenforce` command. It returns 'Enforcing', 'Permissive', or 'Disabled'. For more details, use `sestatus`. To enable enforcing mode, run `setenforce 1` and edit `/etc/selinux/config` to set `SELINUX=enforcing`. The exam expects you to know these commands.

**What is the difference between SUID and sticky bit?**

SUID (Set User ID) allows a program to run with the file owner's privileges, typically root. It is set with `chmod u+s` and can be a security risk if misapplied. The sticky bit (set with `chmod +t`) on a directory like `/tmp` prevents users from deleting or renaming files owned by other users. Both are special permissions tested on the exam.

**How do I harden the Linux kernel against buffer overflow attacks?**

Enable ASLR (Address Space Layout Randomization) by setting `kernel.randomize_va_space=2` in `/etc/sysctl.conf`. Also enable Exec-Shield (`kernel.exec-shield=1`) and disable core dumps (`fs.suid_dumpable=0`). These kernel parameters randomize memory addresses and prevent predictable memory layouts that attackers exploit.

**What is the purpose of the `sudo` command and how do I configure it?**

`sudo` allows authorized users to execute commands as root or another user. It is configured via the `/etc/sudoers` file, edited with `visudo`. Example: `username ALL=(ALL) ALL` gives full sudo access. For least privilege, restrict commands: `username ALL=(ALL) /usr/bin/apt update`. Sudo logs commands to `/var/log/sudo.log` if configured.

**How do I find and remove unnecessary SUID binaries?**

Use `find / -perm -4000` to list all SUID binaries. Review each one to determine if it needs SUID. Remove the SUID bit with `chmod u-s /path/to/binary`. Common unnecessary SUID binaries include `wall`, `chsh`, and `mount`. The exam expects you to know how to identify and mitigate SUID vulnerabilities.

**What is the difference between `systemctl stop` and `systemctl disable`?**

`systemctl stop` immediately halts a running service. `systemctl disable` prevents the service from starting automatically at boot. To fully remove a service from the system, you typically use both commands, and optionally remove the package with `apt remove` or `yum remove`. The exam tests understanding of service management.

---

Interactive version with quiz and diagrams: https://courseiva.com/learn/security-plus/hardening-linux
