COMPLETE WORKBOOK v2.0
Complete Hands-On Student Workbook — Concept-First, Lab-Driven

OS SystemHardening

Every module begins with a clear definition and explanation of why a technique matters — before a single command is run. Understand the principle, then apply it.

16Modules
35+Labs
Ubuntu22.04 LTS
100%Linux
01
Introduction
Foundations of System Hardening

// Learning Objectives

  1. Define system hardening and articulate its purpose in cybersecurity.
  2. Explain the concept of attack surface and how hardening reduces it.
  3. Describe the three core principles: least privilege, defence in depth, minimal footprint.
  4. Distinguish between hardening and patching.
  5. Set up a safe, isolated lab environment for practice.

What Is System Hardening?

When a Linux operating system is installed, it is configured for maximum compatibility — not maximum security. It ships with services you may never use, default accounts that are predictable, open ports that serve no purpose, and settings tuned for convenience rather than defence.

System hardening is the deliberate process of reconfiguring a system to eliminate all unnecessary exposure. The goal is to make a system do exactly what it needs to do — nothing more. Every extra service, open port, unused account, and default setting is a potential doorway for an attacker.

Think of it this way: a bank vault is not just a strong box. It has multiple locked doors, a time lock, motion sensors, a security guard, and reinforced walls. Remove any one layer and the vault becomes easier to breach. System hardening applies the same layered thinking to an operating system.

// Definitions

Attack Surface: All the points where an attacker could try to enter or extract data. This includes open ports, running services, user accounts, installed software, and configuration settings.

System Hardening: The process of reducing the attack surface by removing unnecessary components, tightening configurations, and applying security controls — making a system harder to compromise.

// Why This Matters

A default Ubuntu server may have 500+ installed packages, dozens of running services, and multiple open ports — most of which your application will never use. Each is an opportunity for an attacker. A vulnerability in an unused service is just as dangerous as one in your core application. Hardening forces you to consciously justify everything that stays on the system.

The Three Core Principles

Every hardening decision flows from three principles. Master these and you can make sound security decisions in any situation — even those not covered by a checklist.

🎯

Least Privilege

Every user, process, and service gets only the minimum permissions needed to function. A web server should not run as root. A developer should not have system-wide sudo access.

🛡

Defence in Depth

Layer multiple independent controls. If an attacker bypasses the firewall, access controls still block them. If they gain a user account, they are still blocked from root.

👁

Minimal Footprint

Install, run, and expose only what is necessary. Every extra package and open port is a potential vulnerability. If you do not need it, remove it.

🔄

Continuous Review

Hardening is not a one-time event. New vulnerabilities are discovered daily. Systems change over time. Security posture must be revisited regularly.

LAB 1.1Setting Up Your Lab Environment
⚠ Critical Safety RuleAlways practice hardening on a dedicated virtual machine. Never apply these configurations to a production system or personal computer without fully understanding each change.
Step 1 — Install VirtualBox and Create a VM

Download VirtualBox from virtualbox.org and Ubuntu 22.04 LTS Server ISO from ubuntu.com/download/server. Create a VM with at least 2GB RAM and 20GB disk. Use a minimal server installation — no desktop needed.

Step 2 — Take a Baseline Snapshot

Before any changes, take a snapshot. This is your safety net — if anything goes wrong during a lab, you can instantly revert to a clean state.

bash
In VirtualBox: Machine > Take Snapshot > Name: "Clean-Baseline"
Or via CLI (replace VM_NAME with your VM name):
VBoxManage snapshot "VM_NAME" take "Clean-Baseline"
To restore later if needed:
VBoxManage snapshot "VM_NAME" restore "Clean-Baseline"
Step 3 — Update Your System
bash
Check OS version and kernel
uname -a && cat /etc/os-release
Linux ubuntu 5.15.0-91-generic #101-Ubuntu SMP ...
NAME="Ubuntu" VERSION="22.04.3 LTS (Jammy Jellyfish)"
Apply all available security patches
apt update && apt upgrade -y
Reading package lists... Done

// Knowledge Check — Module 1

  1. Define "attack surface" in your own words. Give two examples of components that contribute to it.Write your answer below ↓
  2. Explain the principle of "least privilege." Why would giving every user admin access be a security risk?
  3. What is the difference between hardening a system and patching it?

02
Minimal Footprint
Package & Software Management

// Learning Objectives

  1. Explain why unnecessary software increases security risk.
  2. Audit installed packages and identify those not required.
  3. Safely remove packages including configuration files.
  4. Identify and remove legacy insecure network protocol packages.

Why Every Installed Package Is a Risk

Every piece of software on a system introduces potential vulnerabilities. Software contains code, and code can have bugs. Some bugs are security vulnerabilities — flaws attackers exploit to gain unauthorised access or escalate privileges.

A default Ubuntu installation includes hundreds of packages for general use. On a dedicated web server, you do not need printing software (CUPS), Bluetooth support, or graphical tools — yet these may be installed and running, silently expanding your attack surface.

The principle: "If it is not needed, it should not be there." This is not about saving disk space — it is about eliminating attack vectors that exist purely by default.

// Why This Matters

In 2021, a vulnerability in the polkit package (CVE-2021-4034, "PwnKit") let any local user gain root access on virtually every major Linux distribution. Many servers had polkit installed by default — even those that never used it. Servers without polkit were completely unaffected. One unnecessary package, one critical compromise.

// Key Distinction

apt remove: Removes the program binaries but leaves configuration files on disk. Those leftover configs can cause confusion or occasionally be exploited.

apt purge: Removes the program AND all its configuration files. Always use purge when hardening — leave no traces of packages you have decided to remove.

LAB 2.1Auditing and Removing Unnecessary Packages
Step 1 — Audit Installed Packages
bash
Count total installed packages
dpkg --get-selections | wc -l
542
Browse all installed packages interactively
dpkg -l | less
Search for a specific package by name
dpkg -l | grep -i telnet
Find packages automatically installed but no longer needed
apt autoremove --dry-run
Step 2 — Remove Insecure Legacy Protocols

These packages provide services that transmit data in plain text — every byte, including passwords, visible to any network observer.

Insecure PackageRiskSecure Replacement
telnetAll data including passwords sent unencryptedSSH (OpenSSH)
ftpUnencrypted file transfer, credentials exposedSFTP or SCP
rsh-clientRemote shell with no encryptionSSH
rloginRemote login with no encryptionSSH
talkUnencrypted network chat protocolN/A — remove
bash
Remove insecure packages AND config files (purge)
apt purge telnet ftp rsh-client rlogin talk -y 2>/dev/null
Remove unneeded server packages
apt purge xinetd nis yp-tools tftpd atftpd -y 2>/dev/null
Clean up orphaned dependencies
apt autoremove -y && apt clean
Verify removal — no output means not found = successfully removed
which telnet

// Knowledge Check — Module 2

  1. Why is telnet considered dangerous even on a private internal network?
  2. What is the difference between apt remove and apt purge? Which should you use when hardening and why?

03
Kernel-Level Defence
Kernel Parameter Hardening (sysctl)

// Learning Objectives

  1. Explain what the Linux kernel is and what sysctl controls.
  2. Identify kernel parameters relevant to network and memory security.
  3. Apply and persist hardened sysctl settings with documented rationale.
  4. Understand the specific attack each parameter mitigates.

The Linux Kernel and Runtime Configuration

The Linux kernel is the core of the OS — the layer between hardware and software. It manages memory, processes, devices, and networking. The kernel decides how the system responds to network packets, how it handles memory, and how processes interact.

Linux exposes kernel settings through a virtual filesystem at /proc/sys/. The sysctl command reads and changes these settings at runtime. Settings persist across reboots when written to files in /etc/sysctl.d/.

Default kernel settings favour compatibility over security. For example, by default the kernel may accept ICMP redirects (used by attackers to manipulate routing) and may not validate packet source addresses (enabling IP spoofing).

// Why This Matters — Specific Attacks Each Parameter Blocks

SYN Flood (tcp_syncookies): Attacker sends thousands of half-open connection requests, exhausting the server's connection table and making it unreachable. SYN cookies allow the server to handle legitimate connections without maintaining state for incomplete ones.

IP Spoofing (rp_filter): Attacker sends packets claiming to come from a trusted address. Reverse path filtering drops packets whose source address would not be reachable via the interface it arrived on — catching most spoofed packets.

Route Hijacking (accept_redirects): Attacker sends ICMP redirect messages to change your routing table, forcing your traffic through their machine. Disabling redirect acceptance eliminates this attack vector entirely.

Memory Exploits (randomize_va_space): ASLR randomises where code, stack, and heap are placed in memory, making it far harder to predict addresses needed for buffer overflow and return-oriented programming attacks.

LAB 3.1Applying Kernel Hardening Parameters
Step 1 — Check Current Values Before Changing
bash
Check a parameter's current value
sysctl net.ipv4.conf.all.accept_redirects
net.ipv4.conf.all.accept_redirects = 1 ← should be 0
sysctl kernel.randomize_va_space
kernel.randomize_va_space = 2 ← good, already at max
sysctl net.ipv4.tcp_syncookies
net.ipv4.tcp_syncookies = 1 ← already enabled on Ubuntu
Step 2 — Create a Dedicated Hardening Config File

We create a new file in /etc/sysctl.d/ rather than editing the main /etc/sysctl.conf. This keeps hardening changes separate, easy to audit, and easy to remove without affecting other settings.

/etc/sysctl.d/99-hardening.conf
=== NETWORK SECURITY ===
This system is not a router — disable packet forwarding
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
Disable ICMP redirects — prevents route manipulation attacks
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
Do not send ICMP redirects (we are not a router)
net.ipv4.conf.all.send_redirects = 0
SYN cookies — protects against SYN flood DoS attacks
net.ipv4.tcp_syncookies = 1
Reverse path filtering — blocks IP spoofing attacks
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
Ignore broadcast pings — prevents Smurf DDoS amplification
net.ipv4.icmp_echo_ignore_broadcasts = 1
Drop source-routed packets — prevents route bypassing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
Log martian (suspicious source) packets for detection
net.ipv4.conf.all.log_martians = 1
=== MEMORY AND PROCESS SECURITY ===
Disable core dumps — prevents memory content leaking to disk
fs.suid_dumpable = 0
ASLR at maximum — randomise address space to defeat memory exploits
kernel.randomize_va_space = 2
Restrict kernel log access to root only
kernel.dmesg_restrict = 1
Hide kernel memory addresses from unprivileged users
kernel.kptr_restrict = 2
Disable SysRq key — prevents certain low-level system key combos
kernel.sysrq = 0
Step 3 — Apply and Verify
bash
Apply all sysctl configs without rebooting
sysctl --system
* Applying /etc/sysctl.d/99-hardening.conf ...
Verify individual settings
sysctl net.ipv4.conf.all.accept_redirects
net.ipv4.conf.all.accept_redirects = 0
sysctl kernel.randomize_va_space
kernel.randomize_va_space = 2
Reboot and re-verify to confirm settings persist
reboot

// Knowledge Check — Module 3

  1. What is a SYN flood attack? How does enabling tcp_syncookies defend against it without breaking legitimate connections?
  2. What is IP spoofing? Which kernel parameter helps prevent it and how does it work?
  3. Why is ASLR (kernel.randomize_va_space = 2) a useful defence against memory-based exploits?

04
File System Controls
File System & Partition Security

// Learning Objectives

  1. Understand Linux file permissions and their security implications.
  2. Find and fix world-writable files and dangerous SUID/SGID binaries.
  3. Harden temporary directories using mount flags.
  4. Explain and apply the sticky bit to shared directories.

Linux File Permissions — The Foundation of Access Control

Every file and directory in Linux has three permission sets: owner, group, and other (everyone else). Each set includes read (r=4), write (w=2), and execute (x=1). Together they form the access control layer that determines what each user can do with each file.

Misconfigured permissions are one of the most common security issues found during Linux audits. A sensitive file readable by all users leaks information. An executable with the SUID bit set unnecessarily can be abused for privilege escalation.

// Key Concepts

SUID (Set User ID, bit 4000): When set on an executable, the program runs with the file owner's permissions (often root) — regardless of who launched it. Legitimate use: passwd needs SUID to modify /etc/shadow. Unnecessary SUID binaries on unexpected files are privilege escalation risks.

SGID (Set Group ID, bit 2000): Similar to SUID but for group. When set on a directory, new files inherit the directory's group rather than the creator's group.

Sticky Bit (bit 1000): On a directory, users can only delete or rename their own files — even if the directory is world-writable. Essential for /tmp to prevent users deleting each other's files.

World-Writable File: A file any user can modify. If a privileged process (e.g., a root cron job) reads or executes this file, an attacker can modify it to inject malicious commands.

// Why This Matters

The /tmp directory is world-writable by design — all users need to create temporary files there. Without the noexec mount flag, an attacker who uploads a malicious script to /tmp can execute it directly. Many privilege escalation techniques specifically target /tmp because it is writable by any user. Mounting /tmp with noexec, nosuid, and nodev eliminates this entire attack class.

LAB 4.1Auditing and Fixing File Permissions
Step 1 — Find World-Writable Files
bash
Find world-writable FILES (excludes /proc and /sys virtual filesystems)
find / -type f -perm -002 -not -path "/proc/*" -not -path "/sys/*" -not -path "/dev/*" 2>/dev/null
Find world-writable DIRECTORIES (excluding expected ones like /tmp)
find / -type d -perm -002 -not -path "/proc/*" -not -path "/sys/*" -not -path "/tmp" -not -path "/var/tmp" 2>/dev/null
Fix a world-writable file: remove write permission from "others"
chmod o-w /path/to/file
Step 2 — Audit SUID and SGID Binaries
bash
Find all SUID (4000) and SGID (2000) binaries and list them
find / -type f \( -perm -4000 -o -perm -2000 \) -not -path "/proc/*" 2>/dev/null -exec ls -la {} \;
-rwsr-xr-x 1 root root 88464 ... /usr/bin/passwd <-- legitimate
-rwsr-xr-x 1 root root 67816 ... /usr/bin/su <-- legitimate
-rwsr-xr-x 1 root root 12345 ... /opt/myapp/custom <-- investigate this!
Remove SUID bit from an unexpected binary
chmod u-s /opt/myapp/custom
Step 3 — Correct Critical System File Permissions
bash
Check current permissions on critical system files
ls -la /etc/passwd /etc/shadow /etc/group /etc/gshadow
-rw-r--r-- 1 root root ... /etc/passwd
-rw-r----- 1 root shadow ... /etc/shadow <-- verify this is 640
Set correct permissions
chmod 644 /etc/passwd
chmod 640 /etc/shadow
chmod 644 /etc/group
chmod 640 /etc/gshadow
chmod 700 /etc/cron.d /etc/cron.daily /etc/cron.weekly /etc/cron.monthly
chmod 600 /etc/crontab
LAB 4.2Hardening /tmp with Mount Options

Mount flags that harden /tmp:

  • noexec — prevents execution of any binary or script from this filesystem
  • nosuid — SUID/SGID bits are ignored — stops privilege escalation via files placed here
  • nodev — prevents creation of device files — blocks device-based exploits
bash
Check current /tmp mount options
mount | grep /tmp
Edit /etc/fstab to harden /tmp permanently
nano /etc/fstab
Add or modify the /tmp line:
tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev 0 0
Apply without rebooting
mount -o remount,noexec,nosuid,nodev /tmp
Verify
mount | grep /tmp
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noexec,relatime)
Test noexec is working — this SHOULD be denied
cp /bin/ls /tmp/testbin && /tmp/testbin
bash: /tmp/testbin: Permission denied <-- Correct! noexec is active
rm /tmp/testbin

05
Perimeter Defence
Network Hardening & Firewall (UFW)

// Learning Objectives

  1. Explain what a firewall does and why deny-by-default is the correct posture.
  2. Audit open ports and map each to its owning service.
  3. Configure UFW with a deny-by-default policy and explicit allow rules.
  4. Test and verify firewall rules are working correctly.

What Is a Firewall and Why Is Port Control Critical?

A firewall is a security control that monitors and filters network traffic based on defined rules. It sits between your system and the network, deciding which connections are permitted and which are blocked.

Every open network port is a potential entry point. Automated scanners continuously search the internet for open ports, then attempt to exploit whatever service is listening. The fewer ports you expose, the smaller your network attack surface.

The golden rule: deny all traffic by default, then explicitly allow only what is required. This approach is categorically safer than allowing everything and trying to block known-bad traffic, because attackers constantly find new attack methods that no blocklist covers yet.

// Why This Matters

Shodan.io and similar scanners index the entire public internet continuously. A new server with a public IP address will receive its first automated port scan within minutes of going online. A default Ubuntu server may expose ports for printing (631), RPC (111), and other services that have no place on a web server. Each gives an attacker another target to probe and potentially exploit.

LAB 5.1Auditing Open Ports
bash
ss: socket statistics — shows all listening TCP/UDP ports + owning process
ss -tulnp
Netid State Local Address:Port Process
tcp LISTEN 0.0.0.0:22 sshd
tcp LISTEN 0.0.0.0:631 cupsd <-- printing on a server?
Find the process using a specific port
lsof -i :631
cupsd 1234 root ... TCP *:631 (LISTEN)
PortServiceNeeded on Server?Action
22SSHYesKeep — harden in Module 8
80/443HTTP/HTTPSOnly if web serverAllow only if running web server
631CUPS PrintingNoDisable CUPS service
111rpcbindOnly for NFSDisable unless NFS is required
25SMTPOnly if mail serverDisable unless running mail
LAB 5.2Configuring UFW Firewall
🚨 Critical WarningAlways allow SSH BEFORE enabling UFW. Enabling the firewall without allowing port 22 will immediately lock you out of remote access.
bash
apt install ufw -y
Set default: deny all incoming, allow all outgoing
ufw default deny incoming
ufw default allow outgoing
Allow SSH BEFORE enabling — critical!
ufw allow 22/tcp comment 'SSH access'
Allow other services this server actually needs
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'
Enable the firewall
ufw enable
Firewall is active and enabled on system startup
Verify rules
ufw status verbose
Block a specific IP after repeated failed logins
ufw deny from 203.0.113.55 to any
Restrict SSH to a trusted IP range only
ufw allow from 192.168.1.0/24 to any port 22

06
Identity & Access Management
User Accounts & Password Policy

// Learning Objectives

  1. Audit all user accounts and identify unnecessary or dangerous ones.
  2. Enforce a strong password policy using PAM and pwquality.
  3. Configure account lockout after repeated failed login attempts.
  4. Apply password ageing to limit the lifespan of compromised credentials.

Why User Account Hygiene Is Critical

User accounts are the identity layer of a system. Attackers targeting a system will almost always try to compromise or create user accounts. Common techniques include brute-forcing passwords, exploiting default accounts, escalating from a low-privilege account to root, and creating backdoor accounts during an intrusion.

Every account should have a clear, current purpose. A departed employee's account, a decommissioned service account, or a default vendor account that was never removed — each is a potential entry point that should no longer exist.

// Why This Matters

Password brute-force attacks are automated and fast. Modern GPUs can test billions of password combinations per second against offline password hashes. A 6-character password can be cracked in seconds. A 14+ character password with mixed complexity requires centuries of compute time with current hardware. Online lockout policies make remote brute-force practically impossible regardless of password length, by blocking the attacker after just a few attempts.

LAB 6.1User Account Audit
bash
List accounts with real interactive login shells
grep -v "/nologin\|/false\|/sync" /etc/passwd
Find any account with UID 0 other than root (very dangerous)
awk -F: '($3 == 0) { print $1 }' /etc/passwd
root
Find accounts with empty passwords (critical vulnerability)
awk -F: '($2 == "" ) { print $1 }' /etc/shadow
Check last login times to spot stale accounts
lastlog | grep -v "Never logged in"
Lock an account (keeps it but blocks login)
passwd -l username
Delete an account and its home directory
userdel -r username
Set shell to nologin to disable interactive access
usermod -s /usr/sbin/nologin username
LAB 6.2Password Policy with PAM and pwquality

PAM (Pluggable Authentication Modules) is Linux's authentication framework. The pam_pwquality module enforces quality requirements when passwords are set, rejecting weak passwords before they are accepted.

bash
apt install libpam-pwquality -y
nano /etc/security/pwquality.conf
/etc/security/pwquality.conf
Minimum 14 characters
minlen = 14
Require at least 1 digit (-1 = required)
dcredit = -1
Require at least 1 uppercase letter
ucredit = -1
Require at least 1 special character
ocredit = -1
Require at least 1 lowercase letter
lcredit = -1
Reject if more than 3 consecutive identical characters
maxrepeat = 3
Reject passwords containing the username
reject_username
Remember last 5 passwords (prevent reuse)
remember = 5
Password Ageing with chage

Password ageing limits how long a compromised credential remains useful. If an attacker steals a hash that takes weeks to crack, an expiry policy ensures the password has changed by the time they crack it.

bash
View current ageing policy for a user
chage -l username
Password expires: never <-- this should have a limit
Set: 90 day max, 7 day min, 14 day warning
chage -M 90 -m 7 -W 14 username
Apply defaults to ALL future new users via /etc/login.defs
nano /etc/login.defs
PASS_MAX_DAYS 90
PASS_MIN_DAYS 7
PASS_WARN_AGE 14
Account Lockout with pam_faillock (Ubuntu 22.04+)
bash
nano /etc/pam.d/common-auth
Add BEFORE the pam_unix line:
auth required pam_faillock.so preauth silent audit deny=5 unlock_time=1800
auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=1800
nano /etc/pam.d/common-account
account required pam_faillock.so
Check failed attempts for a user
faillock --user username
Unlock a locked account
faillock --user username --reset

07
Service Management
Disabling Unnecessary Services

// Learning Objectives

  1. Explain why unnecessary running services increase risk.
  2. Audit all running and enabled services.
  3. Understand the security difference between disabling and masking a service.
  4. Identify which services are appropriate for different server roles.

Services as an Attack Surface

A service (or daemon) is a background process that runs continuously, waiting to perform a task — often handling network requests. Every running service is a potential attack target. If a service has a vulnerability, an attacker can exploit it to gain a foothold on the system.

A fresh Ubuntu install may run 40+ services by default. On a dedicated web server, printing (CUPS), Bluetooth, mDNS announcer (Avahi), and NFS support (rpcbind) all start automatically — none of them needed, all of them potential vulnerabilities.

// Disable vs Mask

Disable: Stops automatic start at boot. The service can still be started manually or triggered by other services. Use when you might occasionally need the service.

Mask: Creates a symlink to /dev/null. The service cannot start by any means — automatic or manual — until explicitly unmasked. Use for services that should NEVER run on this system under any circumstances.

// Why This Matters

The 2017 WannaCry ransomware exploited SMBv1 — a file sharing protocol. Hundreds of thousands of systems had SMBv1 running even though they were not used as file servers. Systems where SMB was disabled or removed were completely immune. One unnecessary service: a global ransomware pandemic affecting 200,000+ computers across 150 countries.

LAB 7.1Auditing and Hardening Services
bash
List all currently RUNNING services
systemctl list-units --type=service --state=running
List all services set to start at boot (enabled)
systemctl list-unit-files --type=service --state=enabled
Read what a service does before disabling it
systemctl cat cups.service | head -20
Disable AND stop in one command
systemctl disable --now cups avahi-daemon bluetooth rpcbind
MASK: makes it impossible to start by any means
systemctl mask cups avahi-daemon bluetooth rpcbind
Verify masking
systemctl status cups
Loaded: masked (/dev/null; bad)
Confirm it cannot be started
systemctl start cups
Failed to start cups.service: Unit cups.service is masked.

08
Remote Access Security
SSH Hardening

// Learning Objectives

  1. Explain why SSH is a high-value attack target and what brute-force means.
  2. Generate an SSH key pair and configure key-based authentication.
  3. Harden sshd_config to disable root login and password authentication.
  4. Apply connection limits, timeouts, and logging improvements.

Why SSH Is the Most Targeted Service on the Internet

SSH (Secure Shell) is the standard tool for remote Linux server administration. Because it provides full system access and is universally deployed, it is one of the most targeted services on the internet. Automated bots continuously scan for port 22 and attempt logins using lists of common usernames and passwords — this is called a credential stuffing or brute-force attack.

SSH key-based authentication replaces passwords with cryptographic key pairs. The private key stays on your local machine. The public key is placed on the server. Authentication proves possession of the private key using mathematics — no password transmitted, no password to brute-force. An attacker without your private key file cannot log in, regardless of what they try.

// Why This Matters

A new cloud server typically receives its first automated brute-force SSH attempt within minutes of going online. Logs on default-configured servers routinely show thousands of failed login attempts per day from bots. The only thing protecting a server with password authentication is whether anyone guesses correctly. Disabling password authentication entirely eliminates this whole attack category — bots cannot brute-force a login method that does not exist.

LAB 8.1Setting Up SSH Key Authentication
⚠ Do This BEFORE Disabling Password AuthComplete key setup and confirm it works BEFORE disabling password authentication. If you disable passwords without a working key, you will lock yourself out permanently.
bash — on YOUR LOCAL machine
Generate a strong Ed25519 key pair (modern, secure algorithm)
ssh-keygen -t ed25519 -C "your_email@example.com"
Enter file to save key: /home/user/.ssh/id_ed25519
Enter passphrase: [enter a strong passphrase]
Copy your public key to the server
ssh-copy-id -i ~/.ssh/id_ed25519.pub student@SERVER_IP
Test key-based login BEFORE disabling passwords
ssh -i ~/.ssh/id_ed25519 student@SERVER_IP
Welcome to Ubuntu 22.04 LTS <-- confirm this works!
LAB 8.2Hardening sshd_config
🚨 WarningAlways validate config with sshd -t before restarting. Keep your current SSH session open while testing in a new session. A broken sshd_config can lock you out.
/etc/ssh/sshd_config
Use SSH protocol v2 only (v1 has critical vulnerabilities)
Protocol 2
Disable root login — admins log in as regular user, then sudo
PermitRootLogin no
Disable password auth — require cryptographic keys only
PasswordAuthentication no
PermitEmptyPasswords no
Restrict which users can connect via SSH
AllowUsers student devops
Disconnect after 3 failed auth attempts
MaxAuthTries 3
Auto-disconnect idle sessions after 5 minutes
ClientAliveInterval 300
ClientAliveCountMax 0
Limit concurrent unauthenticated connection attempts
MaxStartups 10:30:60
Disable features not needed that increase attack surface
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
Increase log detail for security monitoring
LogLevel VERBOSE
bash
Validate syntax before restarting
sshd -t
(no output = no errors = safe to continue)
systemctl restart sshd
systemctl status sshd
Active: active (running)

09
Mandatory Access Control
AppArmor — Application Confinement

// Learning Objectives

  1. Explain the difference between Discretionary and Mandatory Access Control.
  2. Describe what AppArmor is and how it confines applications.
  3. Check AppArmor status and understand enforce vs complain modes.
  4. Enable and enforce AppArmor profiles for common services.

Discretionary vs Mandatory Access Control

Discretionary Access Control (DAC) — the traditional Linux permission model — lets file owners decide who can access their files. It is flexible but has a critical weakness: if a process runs as root, or as a user with broad permissions, it can access anything that user can access. A compromised root process has no additional restrictions.

Mandatory Access Control (MAC) operates independently above DAC. Even a root process is constrained by MAC policies defined by the administrator. MAC specifies exactly what each application is allowed to access — and blocks everything else, regardless of the process's user identity.

AppArmor is Ubuntu's built-in MAC system. It assigns each application a profile — a whitelist of permitted file paths, capabilities, and network operations. If a web server is exploited and an attacker tries to read /etc/shadow, AppArmor blocks it because that path is not in the web server's profile.

// Why This Matters

In 2014, Shellshock allowed code execution through bash. Systems with proper MAC confinement limited the blast radius — even with arbitrary code execution, the compromised processes could not access files or make network connections outside their AppArmor profiles. MAC converts a full system compromise into a contained, limited breach. It is already installed and active on Ubuntu — you just need to ensure all profiles are in enforce mode.

LAB 9.1Checking and Enforcing AppArmor Profiles
bash
Check that AppArmor is loaded and active
systemctl status apparmor
aa-status
apparmor module is loaded.
25 profiles are loaded.
2 profiles are in complain mode. <-- these should be enforce
apt install apparmor-utils apparmor-profiles -y
Switch a profile from complain to ENFORCE mode
aa-enforce /etc/apparmor.d/usr.sbin.nginx
Switch to COMPLAIN mode (for testing/troubleshooting only)
aa-complain /etc/apparmor.d/usr.sbin.nginx
Enforce ALL loaded profiles at once
aa-enforce /etc/apparmor.d/*
Reload after changes
systemctl reload apparmor
View AppArmor denials in system logs
grep "apparmor" /var/log/syslog | grep "DENIED" | tail -20

// Knowledge Check — Modules 7–9

  1. What is the difference between systemctl disable and systemctl mask? Give a real-world example of when you would use each.
  2. Why is disabling password authentication for SSH more secure than simply having a strong password?
  3. Explain MAC in plain language. Why is it powerful even against a process running as root?

10
Privilege Management
Sudo Hardening

// Learning Objectives

  1. Explain why direct root login is dangerous and how sudo improves on it.
  2. Configure sudoers to grant least-privilege access to specific commands only.
  3. Enable sudo logging to create an audit trail of every privileged command.
  4. Identify and remediate dangerous sudo misconfigurations.

The Purpose and Risks of sudo

sudo (superuser do) lets authorised users run commands as root without logging in as root directly. This is a major security improvement: every sudo use is logged by default, users authenticate with their own password rather than the root password, and access can be restricted to specific commands.

However, sudo itself can be misconfigured. Granting a user unrestricted sudo (ALL=(ALL:ALL) ALL) is effectively the same as giving them the root password. The NOPASSWD directive removes even the authentication step. Granting sudo access to text editors, file viewers, or scripting tools enables privilege escalation via their built-in shell escape features.

// Why This Matters — GTFOBins

GTFOBins (gtfobins.github.io) is a security research database documenting how common Unix binaries can be abused for privilege escalation. If a user has sudo vim, they can type :!/bin/bash inside vim to get a root shell. sudo find . -exec /bin/sh \; works the same way with find. The fix: grant sudo access only to the exact commands a user needs for their role — never to general-purpose tools.

LAB 10.1Hardening the Sudoers Configuration
⚠ Always use visudovisudo validates syntax before saving. A syntax error in sudoers can lock out all sudo access. Never edit /etc/sudoers with a regular text editor.
bash
Check what sudo access a user currently has
sudo -l -U username
Find all users in the sudo group
getent group sudo
Create user-specific sudo rules in /etc/sudoers.d/ (preferred over editing main file)
visudo -f /etc/sudoers.d/webadmin
sudoers examples
DANGEROUS: unrestricted sudo with no password
student ALL=(ALL) NOPASSWD: ALL
 
CORRECT: allow only what webadmin actually needs
webadmin ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx
 
Log all sudo commands to a dedicated file
Defaults logfile="/var/log/sudo.log"
Defaults log_input, log_output
 
Require re-authentication after 5 minutes inactivity
Defaults timestamp_timeout=5
 
Prevent environment variable injection attacks
Defaults env_reset
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

11
Boot Security
GRUB Bootloader Hardening

// Learning Objectives

  1. Explain what the GRUB bootloader is and why it requires protection.
  2. Identify the single-user mode bypass attack and its impact.
  3. Password-protect GRUB using a hashed credential.

What Is GRUB and Why Does It Need a Password?

The GRUB bootloader is the first software that runs when a Linux system powers on. It lets you select which OS or kernel to boot and provides access to advanced boot modes including single-user mode (also called recovery mode) — a minimal root shell with no login prompt.

Without a GRUB password, anyone with physical or console access can boot into single-user mode and gain a full root shell in under three minutes. Every other hardening measure becomes irrelevant — file permissions, account controls, AppArmor — none of them apply to someone sitting at a root shell before the full OS has loaded.

This attack requires console or physical access, not network access. But in cloud environments, virtual console access (out-of-band management, KVM, IPMI) may be accessible to a wider group than SSH. Data centres may also have inadequate physical security. GRUB hardening closes this gap.

// Why This Matters

Single-user mode bypass is a standard technique in both penetration testing and real-world attacks. It is used to reset root passwords, extract data, install backdoors, and bypass all login controls. It is one of the fastest ways to take full control of a Linux system. A server that is perfectly hardened at the OS level can be completely compromised in minutes by anyone who can reach a console without GRUB protection.

LAB 11.1Setting a GRUB Password
🚨 WarningRecord your GRUB password securely before proceeding. If you forget it, recovery requires booting from external media. Always test in a VM first.
Step 1 — Generate a Password Hash

Never store plain-text passwords in GRUB configuration. PBKDF2 creates a one-way hash that GRUB can verify without storing the actual password.

bash
grub-mkpasswd-pbkdf2
Enter password: [type your password]
Reenter password: [type again]
PBKDF2 hash of your password is grub.pbkdf2.sha512.10000.AAA...
Copy the entire hash string starting from grub.pbkdf2...
Step 2 — Add Password to GRUB Configuration
bash
nano /etc/grub.d/40_custom
/etc/grub.d/40_custom
set superusers="grubadmin"
password_pbkdf2 grubadmin grub.pbkdf2.sha512.10000.PASTE_YOUR_HASH_HERE
bash
chmod 600 /etc/grub.d/40_custom
update-grub
Generating grub configuration file ...
Reboot and press 'e' at GRUB menu to test — should prompt for credentials

12
Data Protection
Disk Encryption with LUKS

// Learning Objectives

  1. Define encryption at rest and explain when it is necessary.
  2. Describe how LUKS works conceptually.
  3. Create and manage a LUKS-encrypted volume.
  4. Understand the relationship between encryption and other security controls.

What Is Encryption at Rest?

Encryption at rest means data stored on disk is encrypted — unreadable without the correct key, even if someone physically removes the storage device and connects it to another machine. All network security and access controls cannot protect data if an attacker can simply take the hard drive.

LUKS (Linux Unified Key Setup) is the standard disk encryption framework on Linux. It creates an encrypted block device on a partition. When the device is "opened" (unlocked) with the correct passphrase, the OS sees it as a normal filesystem. Without the key, the data is indistinguishable from random noise — mathematically infeasible to decrypt.

// When Encryption at Rest Is Required

Compliance: PCI-DSS requires encryption of cardholder data at rest. HIPAA requires encryption of protected health information. GDPR strongly recommends encryption as a safeguard for personal data.

Physical risk: Laptops are stolen. Server drives are sometimes removed from data centres. Cloud providers have physical access to the underlying hardware. Encryption ensures that physical access to media does not equal access to data.

Defence in depth: If every other security control fails and an attacker obtains the raw storage media, encryption is the final barrier between them and your data.

LAB 12.1Creating a LUKS Encrypted Volume

Add a second virtual disk to your VM in VirtualBox settings (1GB is sufficient for this lab) before starting.

bash
apt install cryptsetup -y
Identify the new disk
lsblk
NAME SIZE TYPE
sda 20G disk
sdb 1G disk <-- our encryption lab disk
Step 1: Initialise LUKS on the disk (destroys all existing data!)
cryptsetup luksFormat /dev/sdb
WARNING! This will overwrite data on /dev/sdb irrecoverably.
Are you sure? (Type 'YES' in capitals): YES
Enter passphrase: [strong passphrase]
Step 2: Open (unlock) the encrypted volume and map it
cryptsetup open /dev/sdb encrypted_data
Enter passphrase for /dev/sdb:
Step 3: Create a filesystem on the unlocked device
mkfs.ext4 /dev/mapper/encrypted_data
Step 4: Mount and use like any normal filesystem
mkdir /mnt/secure && mount /dev/mapper/encrypted_data /mnt/secure
echo "test data" > /mnt/secure/test.txt && cat /mnt/secure/test.txt
test data
Step 5: Unmount and CLOSE (lock) the volume
umount /mnt/secure && cryptsetup close encrypted_data
Without the passphrase the device appears as random encrypted data
file /dev/sdb
/dev/sdb: LUKS encrypted file, ver 2 [...]

// Knowledge Check — Modules 10–12

  1. A junior sysadmin gives a developer the following sudo rule: devuser ALL=(ALL) NOPASSWD: ALL. What is wrong with this? How would you fix it?
  2. Why is GRUB password protection important even on a server with strong SSH hardening?
  3. A company stores medical records on a server. Explain why disk encryption is important even if the server has a firewall, strong passwords, and AppArmor enabled.

13
Visibility & Detection
Auditing, Logging & Fail2ban

// Learning Objectives

  1. Explain why logging is a critical component of a security strategy.
  2. Configure auditd to log specific security-relevant system events.
  3. Identify and use key Linux log files for security analysis.
  4. Set up fail2ban to automatically block brute-force attacks.

Logging: Your Security Eyes and Ears

Hardening reduces the probability of a successful attack, but no system is impenetrable. When an attack occurs — or is attempted — logs are how you find out. They record who did what, when, from where, and whether they succeeded. Without comprehensive logging, you are blind to attacks in progress and unable to investigate incidents after they occur.

auditd is the Linux kernel audit daemon. It intercepts and records system calls — the low-level operations every program must perform. By writing audit rules, you can be alerted any time a sensitive file is modified, a privileged command is executed, or a user account is changed.

Fail2ban monitors log files for patterns of malicious behaviour and automatically adds firewall rules to block the offending source. It converts passive logging into active defence.

// Why This Matters

The average time between a breach occurring and it being detected has historically been measured in months. Comprehensive logging dramatically shrinks this window. A user account logging in at 3am, a configuration file being modified outside maintenance windows, or a privileged command from an unexpected account — these anomalies are visible in logs and can trigger alerts. Without logs, even post-incident forensics is nearly impossible, leaving you unable to understand what was compromised, how, or for how long.

LAB 13.1Configuring auditd for Security Monitoring
bash
apt install auditd audispd-plugins -y
systemctl enable --now auditd
Add audit rules: -w = watch a file, -p = permissions (w=write,a=attr), -k = key for searching
auditctl -w /etc/passwd -p wa -k identity_changes
auditctl -w /etc/shadow -p wa -k identity_changes
auditctl -w /etc/sudoers -p wa -k sudo_changes
auditctl -w /etc/ssh/sshd_config -p wa -k ssh_config
Log all commands run as root (uid=0)
auditctl -a always,exit -F arch=b64 -S execve -F uid=0 -k root_commands
Make rules survive reboot — add to rules file (without 'auditctl' prefix)
nano /etc/audit/rules.d/hardening.rules
-w /etc/passwd -p wa -k identity_changes
-w /etc/shadow -p wa -k identity_changes
-w /etc/sudoers -p wa -k sudo_changes
-a always,exit -F arch=b64 -S execve -F uid=0 -k root_commands
Test: trigger an event and search for it
touch /etc/passwd
ausearch -k identity_changes
Generate an audit summary report
aureport --summary
Log FileWhat It Contains
/var/log/auth.logAll authentication: SSH logins, sudo, su, PAM events
/var/log/syslogGeneral system messages from kernel and services
/var/log/ufw.logFirewall blocks and allows
/var/log/audit/audit.logKernel-level audit events (file access, system calls)
/var/log/faillogFailed login attempt counter per user
/var/log/sudo.logAll sudo commands (if configured in sudoers)
LAB 13.2Configuring Fail2ban
bash
apt install fail2ban -y
Copy default config — never edit jail.conf directly (overwritten on updates)
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
nano /etc/fail2ban/jail.local
jail.local
[DEFAULT]
bantime = 3600 # Ban for 1 hour
findtime = 600 # Look at failures in last 10 min
maxretry = 5 # Ban after 5 failures
backend = systemd
 
[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log
maxretry = 3
bantime = 7200
bash
systemctl enable --now fail2ban
fail2ban-client status sshd
Status for the jail: sshd
|- Filter: Currently failed: 0, Total failed: 0
`- Actions: Currently banned: 0
Test: make 4 failed SSH attempts from another terminal
Then check if your IP was banned
fail2ban-client get sshd banned
Unban your IP after testing
fail2ban-client set sshd unbanip YOUR_IP

14
Intrusion Detection
File Integrity Monitoring with AIDE

// Learning Objectives

  1. Define file integrity monitoring and explain its purpose.
  2. Explain what a cryptographic hash is and why it detects tampering.
  3. Initialise AIDE to create a known-good baseline of the system.
  4. Run integrity checks and correctly interpret changed-file reports.

What Is File Integrity Monitoring?

File Integrity Monitoring (FIM) answers a critical security question: "Has anything on this system changed that should not have?"

FIM works by taking a cryptographic snapshot of every important file when the system is in a known-clean state. A cryptographic hash function (such as SHA-256) generates a unique fixed-length fingerprint from a file's contents. If even one byte changes — whether from a legitimate update, accidental corruption, or an attacker modifying a system binary to install a backdoor — the hash changes. Comparing current hashes to the stored baseline immediately reveals any unauthorised modification.

AIDE (Advanced Intrusion Detection Environment) is a free, open-source FIM tool. It records file content hashes, permissions, ownership, timestamps, and other attributes. Any deviation from the baseline is flagged as a potential intrusion or unauthorised change.

// Why This Matters

Sophisticated attackers who gain root access often modify system binaries to maintain persistent access — replacing /usr/sbin/sshd with a backdoored version that accepts a secret password, or replacing /bin/ls with a version that hides their files. Without FIM, you may never notice. With AIDE, the modification appears immediately on the next check because the file hash no longer matches the baseline. FIM is your defence against this class of attack, and is often required by compliance frameworks like PCI-DSS and HIPAA.

LAB 14.1Setting Up AIDE Integrity Monitoring
bash
apt install aide aide-common -y
Review what AIDE monitors by default
head -80 /etc/aide/aide.conf
Step 1: Initialise the baseline (takes several minutes — scans all monitored files)
aideinit
Running aide --init ...
AIDE initialized database at /var/lib/aide/aide.db.new
Step 2: Promote the new database to become the active baseline
cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
Step 3: Make a deliberate change to test detection
echo "# test" >> /etc/hosts
Step 4: Run an integrity check — compare current state to baseline
aide --check
AIDE found differences between database and filesystem!!
Changed: /etc/hosts
Step 5: Revert your test change
sed -i '$ d' /etc/hosts
Step 6: After legitimate system changes (patches, config updates) update the baseline
aide --update && cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
Automate daily checks via cron
echo "0 3 * * * root /usr/bin/aide --check >> /var/log/aide.log 2>&1" >> /etc/crontab

// Knowledge Check — Modules 13–14

  1. What is a cryptographic hash function? Why does it make file tampering detectable?
  2. When should you update the AIDE baseline? What is the risk of updating it carelessly after an incident?
  3. How does fail2ban complement static firewall rules? What attack does it specifically defend against?

15
Scale & Consistency
Automation & Compliance Scanning

// Learning Objectives

  1. Explain why manual hardening does not scale and automation is essential.
  2. Run a full Lynis security audit and interpret the results.
  3. Write a comprehensive hardening shell script covering all previous modules.
  4. Understand the role of CIS Benchmarks as an industry standard.

Why Automation Is a Security Requirement, Not a Convenience

Manually hardening one server takes hours and introduces human error. A missed step, a typo in a config file, or simply forgetting a module means inconsistent protection. An organisation managing tens, hundreds, or thousands of servers cannot harden them by hand and maintain consistency.

Automation solves this: write the hardening logic once, test it, and apply it uniformly to every server. It is auditable (you can see exactly what was applied), repeatable (a freshly rebuilt server gets the same treatment), and consistent (no forgotten steps).

CIS Benchmarks are industry-standard security configuration guidelines published by the Center for Internet Security. They are the most widely adopted hardening reference globally, with specific technical guidance for every major OS, cloud platform, and application. Many compliance frameworks (PCI-DSS, HIPAA, SOC 2) explicitly reference CIS Benchmarks.

Lynis is an open-source auditing tool that evaluates a system against a large set of security checks, produces a hardening index score, and gives prioritised, specific recommendations. It is the fastest way to get an objective picture of a system's security posture.

LAB 15.1Auditing with Lynis
bash
apt install lynis -y
Run a complete system security audit
lynis audit system
Hardening index : 58 [########### ] <-- your starting score
Review all suggestions
grep "suggestion" /var/log/lynis-report.dat
Focus on a specific area
lynis audit system --tests-from-group authentication
lynis audit system --tests-from-group networking
After hardening: run again and compare scores
lynis audit system
Hardening index : 78 [############### ] <-- improved!

// Lynis Reflection Exercise

  1. Initial Lynis score (before any hardening):
  2. Your top 5 Lynis suggestions:
  3. Score after completing all 14 previous modules:
  4. Which single improvement had the greatest impact on your score?
LAB 15.2The Master Hardening Script

Create a single reusable script that automates the core hardening steps from all previous modules. This is how production environments are hardened at scale — one tested script, applied consistently to every server.

harden-complete.sh
#!/bin/bash
set -euo pipefail
LOGFILE="/var/log/hardening-$(date +%Y%m%d-%H%M).log"
log() { echo "[$(date '+%H:%M:%S')] $1" | tee -a "$LOGFILE"; }
log "=== SYSTEM HARDENING STARTED ==="
 
# MODULE 1: Update system
log "Updating all packages..."
apt-get update -y && apt-get upgrade -y 2>&1 | tail -5 | tee -a "$LOGFILE"
 
# MODULE 2: Remove insecure packages
log "Removing insecure packages..."
apt-get purge telnet ftp rsh-client rlogin -y 2>/dev/null || true
apt-get autoremove -y 2>/dev/null
 
# MODULE 3: Kernel hardening
log "Applying kernel parameters..."
cat > /etc/sysctl.d/99-hardening.conf << 'SYSCTL'
net.ipv4.ip_forward = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
kernel.randomize_va_space = 2
kernel.dmesg_restrict = 1
fs.suid_dumpable = 0
SYSCTL
sysctl --system > /dev/null && log "Kernel parameters applied"
 
# MODULE 4: File permissions
log "Setting critical file permissions..."
chmod 644 /etc/passwd /etc/group
chmod 640 /etc/shadow /etc/gshadow
chmod 600 /etc/crontab
chmod 700 /etc/cron.d /etc/cron.daily /etc/cron.weekly 2>/dev/null || true
 
# MODULE 5: Firewall
log "Configuring UFW firewall..."
apt-get install -y ufw > /dev/null
ufw --force reset > /dev/null
ufw default deny incoming && ufw default allow outgoing
ufw allow 22/tcp
ufw --force enable
 
# MODULE 7: Disable services
log "Disabling unnecessary services..."
for svc in cups avahi-daemon bluetooth rpcbind; do
systemctl disable --now "$svc" 2>/dev/null || true
systemctl mask "$svc" 2>/dev/null || true
done
 
# MODULE 9: AppArmor
log "Enforcing AppArmor profiles..."
apt-get install -y apparmor-utils > /dev/null
aa-enforce /etc/apparmor.d/* 2>/dev/null || true
 
# MODULES 13+: Install security tools
log "Installing auditd and fail2ban..."
apt-get install -y auditd fail2ban > /dev/null
systemctl enable --now auditd fail2ban
 
log "=== HARDENING COMPLETE ==="
log "Running Lynis quick check..."
which lynis > /dev/null 2>&1 && lynis audit system --quick 2>/dev/null \
| grep "Hardening index" | tee -a "$LOGFILE"
log "Full log: $LOGFILE"
bash
chmod +x harden-complete.sh
./harden-complete.sh
[10:31:05] === SYSTEM HARDENING STARTED ===
[10:31:08] Updating all packages...
[10:31:45] Kernel parameters applied
[10:32:02] Configuring UFW firewall...
[10:32:10] === HARDENING COMPLETE ===

16
Final Assessment
Capstone: Harden a Vulnerable System
CAPSTONEFull Hardening Assessment — No Guided Steps
ℹ ScenarioYour instructor has provided a VM snapshot: "Vulnerable-Server-v1". It simulates a poorly configured server freshly deployed to production. Your task is to apply everything from this workbook — independently, without being told what specific problems exist. This mirrors a real hardening engagement.

Complete all tasks independently, in any order:

// Final Reflection

  1. Before this workbook, how would you have described system hardening? How has your understanding changed?
  2. Which hardening technique has the highest impact for the least effort? Justify your answer.
  3. Describe a scenario where hardening alone is insufficient. What complementary controls are needed?
  4. If you needed to harden 50 servers for a new organisation, what would your approach be? What tools and processes would you use?
  5. Which module topic do you want to explore further? Why?
// Master Reference — Essential Commands
CategoryCommandPurpose
Packagesapt purge <pkg>Remove package and all config files
Kernelsysctl --systemApply all /etc/sysctl.d/ settings
Portsss -tulnpList all listening services with PID
Firewallufw status verboseShow all firewall rules and policy
Servicessystemctl mask <svc>Permanently prevent a service from running
Userspasswd -l <user>Lock a user account
SSHsshd -tValidate SSH config syntax before restart
AppArmoraa-enforce /etc/apparmor.d/*Enforce all AppArmor profiles
Sudovisudo -f /etc/sudoers.d/userSafely edit per-user sudo rules
Encryptioncryptsetup luksFormat /dev/sdbCreate LUKS encrypted volume
Auditausearch -k <key>Search audit log by rule key
Fail2banfail2ban-client status sshdSSH jail status and banned IPs
AIDEaide --checkRun file integrity check vs baseline
Lynislynis audit systemFull system security audit with score
Permissionsfind / -perm -4000 2>/dev/nullFind all SUID binaries
Permissionsfind / -perm -002 2>/dev/nullFind world-writable files