Skip to content
intermediate Phase 3 · Operating System Hardening and Permissions

Service Reduction and Host Firewalls

Disable unused services and filter inbound traffic on the host itself.

50m
0 problems
Topic Progress 0%

Every Running Service Is an Attack Surface

The Daemon You Forgot About

Every running service is a potential entry point for an attacker. The more services you run, the larger your attack surface — and the more vulnerabilities you must patch, monitor, and maintain. Service reduction is the process of identifying and disabling every service that is not strictly required for the system's function.

Enumerating Running Services

Before you can reduce services, you need to know what is running:

# List all listening ports and their processes
ss -tlnp    # TCP listening
ss -ulnp    # UDP listening
netstat -tlnp  # Alternative (deprecated on some systems)

# List all running services (systemd)
systemctl list-units --type=service --state=running

# List all enabled services (start at boot)
systemctl list-unit-files --type=service --state=enabled

# Check a specific service
systemctl status apache2

The output reveals services you may not know are running — a test database server, a file sharing service, a remote access tool left over from a previous project.

Identifying Unnecessary Services

For each running service, ask:

  1. Is this service required for the system's function? A web server needs Apache or Nginx. It does not need FTP, Telnet, or a print server.

  2. When was this service last used? If no one has connected to the FTP server in six months, it is a candidate for removal.

  3. Does this service have known vulnerabilities? Check the service name and version against the CVE database. If it has unpatched critical vulnerabilities and is not needed, remove it.

  4. Could this service be replaced by a more secure alternative? Replace Telnet with SSH, FTP with SFTP, HTTP with HTTPS.

  5. Does this service run with excessive privileges? A service running as root that only needs user-level access is a privilege escalation risk.

Common unnecessary services on a hardened Linux server:

Service Port Risk Action
Telnet 23 Plaintext credentials Remove
FTP 21 Plaintext credentials Replace with SFTP
rsh/rlogin 513/514 No encryption, weak auth Remove
NFS 2049 Often misconfigured Disable if not needed
SMB 445 Lateral movement vector Disable if not needed
CUPS 631 Print server — not needed on servers Remove
Avahi/mDNS 5353 Information disclosure Remove
Bluetooth various Not needed on servers Remove

Disabling and Removing Services

# Stop a service immediately
systemctl stop telnet

# Prevent it from starting at boot
systemctl disable telnet

# Remove the package entirely (preferred — eliminates the code)
apt remove telnetd
apt purge telnetd  # Also removes config files

# Mask a service (prevents manual start too)
systemctl mask telnet

Stopping vs. removing: Stopping a service prevents it from running, but the code is still on disk and can be restarted. Removing the package eliminates the code entirely, which is more secure because it cannot be exploited even if an attacker gains access to the system.

The Principle of Minimal Installation

The most effective service reduction happens before the operating system is installed. Use a minimal installation:

  • Linux: Install only the base system, then add only the packages you need. Most distributions offer a "minimal" or "server" installation option.
  • Windows: Use Server Core (no GUI) for servers. The GUI is not needed for most server roles and adds hundreds of unnecessary services and libraries.
  • Containers: Use distroless or alpine-based images that contain only the application and its dependencies.
# Check what packages are installed
dpkg -l | wc -l    # Debian/Ubuntu
rpm -qa | wc -l   # RHEL/CentOS

# Remove unnecessary packages
apt autoremove     # Remove unused dependencies

A minimal installation has fewer services, fewer packages, fewer vulnerabilities, and a smaller patch surface. It is easier to secure because there is less to monitor and maintain.

Host Firewalls: Default-Deny at the Host Level

Why Network Firewalls Are Not Enough

A network firewall protects the perimeter, but it cannot protect against threats that are already inside the network. If an attacker breaches the web server and tries to pivot to the database server on the internal network, the network firewall may allow the traffic because it is inside the trusted perimeter.

A host firewall provides a second layer of defense at the host itself. Even if the network perimeter is breached, the host firewall controls what can connect to the host.

Default-Deny Host Firewall Configuration

The fundamental principle: block all inbound traffic by default, then allow only what is explicitly required.

Linux — iptables:

#!/bin/bash
# Default-deny host firewall for a web server
# Flush existing rules
iptables -F
iptables -X

# Default policies: drop all inbound, allow all outbound
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Allow established connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow loopback
iptables -A INPUT -i lo -j ACCEPT

# Allow SSH from management network only
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/24 -j ACCEPT

# Allow HTTP and HTTPS from anywhere
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Allow ICMP (ping) — optional, but useful for monitoring
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# Log dropped packets
iptables -A INPUT -j LOG --log-prefix "IPTABLES-DROP: " --log-level 4

# Save rules (Debian/Ubuntu)
iptables-save > /etc/iptables/rules.v4

Linux — nftables (modern replacement for iptables):

#!/bin/bash
# nftables default-deny for a web server
nft flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        
        # Allow established connections
        ct state established,related accept
        
        # Allow loopback
        iif lo accept
        
        # Allow SSH from management network
        tcp dport 22 ip saddr 10.0.0.0/24 accept
        
        # Allow HTTP/HTTPS
        tcp dport { 80, 443 } accept
        
        # Drop and log everything else
        log prefix "NFT-DROP: " drop
    }
    
    chain output {
        type filter hook output priority 0; policy accept;
    }
    
    chain forward {
        type filter hook forward priority 0; policy drop;
    }
}

Windows — Windows Firewall (PowerShell):

# Set default inbound policy to block
Set-NetFirewallProfile -Profile Domain,Public,Private -DefaultInboundAction Block

# Allow SSH from management network
New-NetFirewallRule -DisplayName "Allow SSH" `
    -Direction Inbound -Protocol TCP -LocalPort 22 `
    -RemoteAddress 10.0.0.0/24 -Action Allow

# Allow HTTP/HTTPS
New-NetFirewallRule -DisplayName "Allow HTTP" `
    -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow
New-NetFirewallRule -DisplayName "Allow HTTPS" `
    -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow

Firewall Rule Design Principles

  1. Specific over general: Allow traffic from specific IPs to specific ports, not from anywhere to anywhere.

  2. Least privilege: Open only the ports that are required. If the web server does not need inbound MySQL (3306), block it.

  3. Direction matters: Inbound rules control what can connect to the host. Outbound rules control what the host can connect to. Both matter — an attacker who compromises the host will try to establish outbound connections for command-and-control.

  4. Log dropped packets: Dropped packets that are logged provide visibility into scanning activity and attack attempts. Without logging, you are blind to probes against your firewall.

  5. Test before deploying: A firewall rule that blocks SSH will lock you out if you are managing the server remotely. Always have a console or out-of-band management access when testing firewall rules.

Running Services Under Unprivileged Accounts

Even with a firewall, a compromised service can cause damage if it runs with excessive privileges. The principle: every service should run under a dedicated, unprivileged account.

# Check what user a service runs as
ps aux | grep apache2
# Output: root  1234  ...  /usr/sbin/apache2
#         www-data  5678  ...  /usr/sbin/apache2

# The master process runs as root (needed to bind to port 80),
# but worker processes run as www-data

# Create a dedicated user for a service
useradd -r -s /usr/sbin/nologin myapp
# -r: system account (no home directory, low UID)
# -s /usr/sbin/nologin: cannot log in

# Run the service as the dedicated user
# In the systemd service file:
# [Service]
# User=myapp
# Group=myapp

Why this matters: If an attacker exploits a vulnerability in the service, they gain the privileges of the service's user — not root. An unprivileged user cannot modify system files, install software, or access other users' data. The blast radius is limited to the service's own files and data.

Service Reduction and Firewall Audit Script

#!/bin/bash
# Service reduction and firewall audit

echo "=== Listening Ports ==="
ss -tlnp
echo ""
ss -ulnp

echo ""
echo "=== Enabled Services ==="
systemctl list-unit-files --type=service --state=enabled

echo ""
echo "=== Services Running as Root ==="
for service in $(systemctl list-units --type=service --state=running --no-legend | awk '{print $1}'); do
  user=$(systemctl show -p User --value $service)
  if [ -z "$user" ] || [ "$user" = "root" ]; then
    echo "Service running as root or default: $service"
  fi
done

echo ""
echo "=== Firewall Status ==="
iptables -L -n -v

Practice Problems

0 / 2 solved

Solution
Services to remove: (1) vsftpd (FTP, port 21) — transmits credentials in plaintext, not needed for a web application. Remove: apt purge vsftpd. (2) cupsd (CUPS print server, port 631) — not needed on a server, has a history of vulnerabilities. Remove: apt purge cups. (3) avahi-daemon (mDNS, port 5353) — broadcasts information about the server on the local network, useful for attackers performing reconnaissance. Remove: apt purge avahi-daemon. Services to keep but restrict: (1) sshd — needed for administration, but restrict to management IPs via firewall. (2) apache2 — required for the web application. (3) mysql — the database is on a separate server, so mysql should NOT be running on this server at all. Remove: apt purge mysql-server. The firewall should allow inbound 22 (from management IPs only), 80, and 443 (from anywhere). All other ports should be blocked.

Solution
When the application runs as root, the attacker's code execution has root privileges. The attacker can: read and modify any file on the system (including /etc/shadow, SSH keys, and configuration files); install kernel-level persistence (rootkits); disable security tools (EDR, firewalls); create new user accounts; modify cron jobs; and pivot to other systems using the server's credentials. When the application runs as an unprivileged user (e.g., www-data), the attacker's code execution has only that user's privileges. The attacker can: read and modify the application's own files; access the database if the application's credentials are accessible; but cannot modify system files, install software, or access other users' data. The blast radius is limited to the application's own scope. Implementation: create a dedicated user (useradd -r -s /usr/sbin/nologin myapp), change file ownership (chown -R myapp:myapp /var/www/myapp), and configure the service to run as that user (in systemd: User=myapp, Group=myapp).

Quiz

1. Why is a host firewall necessary even when a network firewall is already in place?

Question 1 options

2. What is the difference between stopping a service and removing its package, and why is removal preferred?

Question 2 options

3. Why should services run under dedicated unprivileged accounts rather than root?

Question 3 options

Flashcards

Question

What is service reduction and why is it important?

Answer

Identifying and disabling every service not strictly required for the system's function. Important because every running service is a potential attack surface — fewer services means fewer vulnerabilities to patch and monitor.

Question

What is the principle of a default-deny host firewall?

Answer

Block all inbound traffic by default, then allow only what is explicitly required. This is the opposite of allow-all-with-exceptions, which is ineffective because you cannot enumerate all malicious traffic.

Question

Why is a host firewall necessary even with a network firewall?

Answer

A network firewall protects the perimeter but cannot prevent lateral movement within the internal network. A host firewall provides a second layer of defense at the host level, blocking unauthorized connections even if the perimeter is breached.

Question

What is the difference between stopping a service and removing its package?

Answer

Stopping prevents it from running but the code remains on disk (can be restarted or exploited). Removing eliminates the code entirely (cannot be exploited). Removal is preferred for security.

Question

Why should services run under dedicated unprivileged accounts?

Answer

If the service is compromised, the attacker gains only the unprivileged user's permissions, limiting the blast radius. A compromised root-running service gives the attacker full system control.

Question

What are the key principles of firewall rule design?

Answer

Specific over general (specific IPs to specific ports), least privilege (open only required ports), direction matters (inbound and outbound), log dropped packets, test before deploying.

Revision Notes

Key Takeaways

  • 1. Every running service expands the attack surface — disable or remove what is not needed
  • 2. Stopping a service leaves the code on disk; removing the package eliminates it entirely
  • 3. A host firewall provides defense in depth — it protects against lateral movement when the perimeter is breached
  • 4. Default-deny is the only effective firewall posture: block all, allow only required
  • 5. Services should run under dedicated unprivileged accounts to limit blast radius
  • 6. Minimal installation (no GUI, minimal packages) is the most effective service reduction

Interview Tips

  • • Be ready to list common unnecessary services and explain the risk of each
  • • Explain how you would design a default-deny firewall for a specific server role
  • • Discuss why a host firewall is necessary even when a network firewall exists
  • • Describe how running services under unprivileged accounts limits the impact of a compromise
  • • Connect service reduction to patching — fewer services means fewer vulnerabilities to patch

Cheat Sheet

Service Reduction and Host Firewalls Cheat Sheet

Phase: Operating System Hardening and Permissions | Level: intermediate

Service Reduction:

  • Every running service is an attack surface — reduce to minimum
  • Enumerate: ss -tlnp, systemctl list-units --type=service
  • Remove unnecessary: Telnet (23), FTP (21), CUPS (631), Avahi (5353)
  • Stop vs. remove: stopping leaves code on disk; removing eliminates it
  • Prefer minimal installation (no GUI, minimal packages)

Host Firewall (Default-Deny):

# iptables default-deny for a web server
iptables -P INPUT DROP
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -j LOG --log-prefix "DROP: "

Firewall Design Principles:

  • Specific over general (specific IPs to specific ports)
  • Least privilege (open only required ports)
  • Direction matters (inbound AND outbound)
  • Log dropped packets
  • Test before deploying (avoid locking yourself out)

Unprivileged Service Accounts:

  • Create: useradd -r -s /usr/sbin/nologin myapp
  • Configure: User=myapp in systemd service file
  • Limits blast radius: compromised service = unprivileged user, not root

Continue Learning

Before You Start

  • No prerequisites listed.