Hardening a Linux system

Listen to this lesson

Episode 24 · 57:55

This episode is a study companion for CompTIA Linux+ XK0-006 and is not produced by or endorsed by CompTIA.

Objective 3.3 · Security · 18% of the exam

Why this matters

Hardening is the work of reducing what an attacker can reach and what they can do once they arrive. It is unglamorous, mostly consists of turning things off, and is the difference between a break-in that is contained and one that owns the machine.

The theme running through all of it is least privilege: every service should have the smallest possible set of capabilities, every account the smallest set of rights, every filesystem the smallest set of permitted operations. Each control below is one application of that idea.

The lesson

Confining a process with chroot

chroot changes a process's apparent root directory. Inside, / is really /srv/jail, and paths above it simply do not exist as far as that process is concerned.

mkdir -p /srv/jail/{bin,lib,lib64,etc}
cp /bin/bash /srv/jail/bin/
ldd /bin/bash                       # find the libraries it needs
# copy each one into the matching path under /srv/jail
chroot /srv/jail /bin/bash

The fiddly part is that a chroot needs everything the program requires inside it — the binary, its shared libraries, and often /etc/passwd, /dev/null and the timezone data. ldd lists the libraries; missing one produces "no such file or directory" for a file that is plainly there, because it is the library that is missing, not the binary.

Its everyday use is confining SFTP users to their own directory:

Match Group sftpusers
    ChrootDirectory /srv/sftp/%u
    ForceCommand internal-sftp

A chroot is containment, not a security boundary. A process running as root inside one can escape — the technique is well known and short. Treat it as defence in depth. For a real boundary use containers with user namespaces, or a virtual machine.

Note also ChrootDirectory must be owned by root and not writable by the user, or sshd refuses it. That surprises people setting one up for the first time.

fail2ban

Even with key-only SSH, a public server sees constant authentication attempts. fail2ban watches log files and adds a firewall rule against addresses that fail repeatedly.

dnf install fail2ban        # or: apt install fail2ban
systemctl enable --now fail2ban
fail2ban-client status
fail2ban-client status sshd
fail2ban-client set sshd unbanip 203.0.113.5
# /etc/fail2ban/jail.local  — not jail.conf, which packages overwrite
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 10.0.0.0/8

[sshd]
enabled = true

The three numbers work together: maxretry failures within findtime results in a ban of bantime.

Put ignoreip in before you enable it, listing your own networks. fail2ban cannot tell your fat-fingered password from an attacker's, and banning yourself from a remote server is a genuinely common self-inflicted outage.

Edit jail.local rather than jail.conf: the latter is package-owned and replaced on update.

fail2ban reduces noise and blunts brute-forcing. It is not a substitute for key authentication — it is what you run in addition, because it also covers web logins, mail and anything else that logs failures.

Disabling unused filesystems

The kernel supports dozens of filesystem types you will never use. Each is code that can contain a vulnerability, reachable by anyone who can get the kernel to try mounting something — which includes plugging in a USB device.

# /etc/modprobe.d/hardening.conf
install cramfs /bin/true
install freevxfs /bin/true
install jffs2 /bin/true
install hfs /bin/true
install hfsplus /bin/true
install squashfs /bin/true
install udf /bin/true
install usb-storage /bin/true      # blocks USB mass storage entirely

install <module> /bin/true is stronger than blacklist: blacklist only stops automatic loading, while this makes any load attempt run /bin/true and succeed at doing nothing. That distinction is what CIS benchmarks are after and it appears in audit findings.

This is standard in benchmark hardening. Test before deploying — squashfs is required by snap packages, and disabling it on Ubuntu breaks them.

Removing unnecessary SUID permissions

A setuid-root binary runs as root regardless of who invokes it. Every one is a potential escalation route, and distributions ship more than they need.

find / -perm -4000 -type f 2>/dev/null      # setuid
find / -perm -2000 -type f 2>/dev/null      # setgid
find / -perm -4000 -type f -newer /etc/hostname 2>/dev/null   # recently changed

Legitimate ones include passwd, sudo, su, mount, ping (on older systems) and pkexec. Candidates to remove the bit from, if unused, are things like chsh, chfn, newgrp, wall and write:

chmod u-s /usr/bin/chsh

Take a baseline and compare. The real value is detection rather than prevention:

find / -perm -4000 -type f 2>/dev/null | sort > /root/suid-baseline.txt
# later
find / -perm -4000 -type f 2>/dev/null | sort | diff /root/suid-baseline.txt -

A new setuid-root binary that nobody installed is one of the clearest indicators of compromise there is — it is how an attacker keeps root after losing their original foothold. A weekly diff catches it.

Do not blanket-remove setuid bits. Strip it from sudo or passwd and you have broken privilege escalation and password changes respectively.

Secure boot and UEFI

UEFI — the Unified Extensible Firmware Interface — replaced BIOS. It boots from an EFI System Partition, requires GPT, supports disks beyond 2 TB, and adds a security feature BIOS had no equivalent of.

Secure Boot requires that every component in the boot chain is signed by a key the firmware trusts. The firmware verifies the bootloader, the bootloader verifies the kernel, the kernel verifies its modules. An unsigned or modified component is refused.

The threat it addresses is the bootkit — malware that loads before the operating system and therefore before any of its defences. Nothing running inside a compromised OS can reliably detect that, because the thing doing the detecting was started by the thing doing the lying. Secure Boot is the only control that acts earlier.

mokutil --sb-state                  # is Secure Boot enabled?
bootctl status                      # boot loader and EFI details
efibootmgr -v                       # boot entries
ls /sys/firmware/efi                # exists = booted in UEFI mode, not legacy

That last check is a quick way to answer "is this machine actually in UEFI mode?" — the directory only exists when it is.

The practical friction is third-party kernel modules. Build NVIDIA's driver, or a DKMS module, on a Secure Boot system and it will not load: it is unsigned. The correct fix is to enrol your own Machine Owner Key and sign the module:

mokutil --import /root/MOK.der      # enrol a key; requires a reboot to confirm
kmodsign sha512 /root/MOK.priv /root/MOK.der module.ko

Disabling Secure Boot is the common shortcut and it discards the protection entirely. Sign the module instead.

Where to start

Rather than inventing a policy, follow a published benchmark — CIS Benchmarks or DISA STIGs — and use tooling to measure against it:

oscap xccdf eval --profile cis --report report.html \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

Benchmarks are opinionated and some controls will not suit your environment. Read each finding, decide, and document the exceptions. A hardening standard with recorded, reasoned exceptions is far more useful than one everybody quietly ignores.

On the exam

  • chroot confines a process's filesystem view; it is not a security boundary and a root process can escape.
  • fail2ban bans after maxretry failures within findtime, for bantime. Configure ignoreip first, and edit jail.local not jail.conf.
  • install <module> /bin/true in /etc/modprobe.d/ is stronger than blacklist, which only prevents automatic loading.
  • find / -perm -4000 locates setuid binaries; a new one you did not install is a strong indicator of compromise.
  • Do not strip setuid from passwd or sudo.
  • Secure Boot verifies signatures through the boot chain and defends against bootkits, which nothing running inside the OS can reliably detect.
  • /sys/firmware/efi exists only when booted in UEFI mode.
  • Sign your kernel modules with a MOK rather than disabling Secure Boot.

Practise what you just read

1. How should chroot be described in a security discussion?

Select one

  1. A filesystem-view restriction, not a security boundary a root process cannot escape
  2. A mandatory access control policy applied to a directory tree
  3. A complete isolation mechanism equivalent to a container
  4. A kernel namespace that isolates processes and networking
Show answer

A. chroot changes what a process sees as its root directory, which is useful for confining a service and essential for rescue work. It is not a sandbox: a process running as root inside one can escape by well-known means. Containers add namespaces and cgroups, and even those are weaker isolation than a virtual machine.

2. Which fail2ban file should local configuration changes be written to?

Select one

  1. jail.local, which overrides jail.conf
  2. Any file placed under the /var/lib/fail2ban/ directory
  3. fail2ban.conf, which is where the jails are defined
  4. jail.conf, which is the package's primary configuration
Show answer

A. jail.conf belongs to the package and is replaced on update, taking your edits with it. jail.local is read afterwards and overrides it, so only your changes live there. Set ignoreip to include your own management network before enabling anything, or the first mistyped password locks you out of your own server.

3. During an audit you find a setuid root binary in /tmp that no package installed. How should this be treated?

Select one

  1. As a permissions error, to be corrected with chmod
  2. As expected, since /tmp is world-writable by design
  3. As a harmless artefact of a failed package installation
  4. As a strong indicator of compromise
Show answer

D. A setuid root binary is a stored route back to root, which is exactly what an intruder leaves behind. Deleting it destroys evidence and does nothing about how it got there. Suspected compromise is an escalation, not an investigation to conduct alone -- preserve the system, and follow the incident process.

5 more questions on this objective are part of the full course.

Practise the full question bank in the exam simulator

Hands-on labs

All hands-on labs