UNIX / Linux keyboard.

How To Harden a Linux or OpenBSD Installation

Hardening Linux and OpenBSD

So you have started using Linux, maybe using my suggestions for getting started, or maybe you're even using OpenBSD. Good for you! OpenBSD is pretty secure by default, but Linux distributions can benefit from further hardening. Let's be careful! Here are some suggestions for hardening typical Linux systems. Many of these work on both Linux and OpenBSD. Some are only relevant on Linux. Suggestions here are divided into:

Green
Everyone should apply these! Unless you really want to be hacked.
Yellow — Cautious
For the more cautious — do these if you are a little worried about being hacked.
Red
For the truly paranoid.

There are no guarantees for what you find here. Remember that security and convenience are usually inversely proportional. If one goes up, the other goes down. Good luck...


Before you start

Green — everyone

Make sure that you have rescue media available.

Especially before continuing with these suggestions.

Linux — try the Knoppix rescue media, or use your install media and choose its rescue option.

OpenBSD — remember that the install CD functions as rescue media.


Update your kernel and applications

Update the kernel, applications, and shared libraries

Green — everyone

Make sure that you apply all security updates!

Red Hat, Fedora, CentOS, and other Red Hat derivatives:

# yum upgrade

Debian, Ubuntu, Knoppix, and other Debian derivatives:

# apt-get update
# apt-get dist-upgrade 

Mageia:

# urpmi.update -a
# urpmi --auto-select 

OpenBSD:

# pkg_add -u 

Also see my page on how to patch and rebuild the OpenBSD kernel.


Harden the kernel's TCP/IP stack

Yellow — Cautious

See my page on kernel stack hardening suggestions.


Protect against network threats

Disable unneeded accounts

Green — everyone

Attackers are attempting to login to your system via SSH as common default accounts like test, admin, guest, and root. Browse through /etc/passwd and disable all unneeded accounts. At least disable these, if they exist.

Remember that you should do both:
— Set the user's shell to /bin/false or similar
— Lock the account so that it has no valid password, see passwd -l on Linux.

Also make very certain that root has a strong password!

Yellow — Cautious

Do the above, and also disable remote root access over SSH.

Make /etc/ssh/sshd_config contain the line:

PermitRootLogin no 

and signal your SSH daemon to reload its configuration:

# /etc/init.d/sshd reload
   -- or --
# systemctl reload sshd 

Disable unneeded network services

Green — everyone

Use lsof to list your system's open TCP and UDP ports. Run this as root since unprivileged users may not be allowed to view sockets they do not own:

# lsof -i 

Every one of those open ports is a risk. Do you really need to run every TCP/UDP service? Turn off what you do not need! You definitely should not run Telnet or any of the Berkeley R* services (rlogin, rcp, rsh).

For standalone services like HTTP/HTTPS, stop and disable the service:

Linux:

# systemctl stop httpd
# systemctl disable httpd 

Old Linux:

# /etc/init.d/httpd stop
# chkconfig --del httpd 

OpenBSD:

# pkill -TERM httpd 

Then edit /etc/rc.conf and insert:

httpd_flags="NO" 

For services run out of inetd (some Linux distributions, OpenBSD), comment out the line in /etc/inetd.conf and signal inetd to re-read its configuration:

# vi /etc/inetd.conf
# pkill -HUP inetd 

For services run out of xinetd (most Linux distributions), edit the specific configuration script and signal xinetd to reload its configuration:

# vi /etc/xinetd.d/wu-ftpd
	change disable = no to disable = yes
# pkill -HUP xinetd 

Repeat this as needed for all xinetd network services you want to shut off.

Yellow — cautious

By the time you finish, your lsof -i output contains little more than the following. Note that you may get one line each for IPv4 and IPv6 (OpenBSD) or just one line saying "IPv6" if it's running a dual stack or "IPv4" if it's IPv4-only (Linux):

COMMAND  PID USER  FD TYPE DEVICE SIZE NODE NAME
sshd    6502 root  3u IPv4 64002       TCP  *:ssh (LISTEN)
sshd    6502 root  3u IPv6 64003       TCP  *:ssh (LISTEN) 

Protect your machine with iptables rules (Linux only)

Green — everyone

Assuming there is no reference to /etc/rc.d/rc.firewall in any existing boot script, do the following. And if there is a reference, then either remove those references or use a different name in the following.

1 — Start a firewall script:
touch /etc/rc.d/rc.firewall
chmod 700 /etc/rc.d/rc.firewall

2 — Let's say your goal is:

Write your firewall script something like the following. Modify the IP ranges and services, and add ACCEPT rules as needed:

#!/bin/sh

# Flush any existing rules and set the default policies:
# Silently drop each packet coming in or through this system,
# unless there is a good reason to accept it.
iptables -F
iptables -P INPUT   DROP
iptables -P OUTPUT  ACCEPT
iptables -P FORWARD DROP 

# Accept anything from myself
iptables -A INPUT -s 127.0.0.1/32 --jump ACCEPT 
# Allow myself to be a non-passive FTP client
iptables -A INPUT -p tcp --dport ftp-data --jump ACCEPT 

# Do not allow a local user to connect to a remote Telnet
# server and thus give away login and password information:
iptables -A OUTPUT -p tcp --dport telnet --jump REJECT 

# Accept SSH connections from 128.46.0.0/16 and 44.48.40.12
iptables -A INPUT -s 128.46.0.0/16  -p tcp --dport ssh --jump ACCEPT 
iptables -A INPUT -s 44.48.40.12/32 -p tcp --dport ssh --jump ACCEPT 

# Accept HTTP connections from 128.46.144.0/24
iptables -A INPUT -s 128.46.144.0/16  -p tcp --dport http  --jump ACCEPT 
iptables -A INPUT -s 128.46.144.0/16  -p tcp --dport https --jump ACCEPT 

# Allow this machine to be a client:
iptables  -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Report what happened
echo 'Firewall rules installed:' 
iptables -L 

3 — Experiment with running that script directly and testing.

4 — When you are certain it works, add a line to the end of /etc/rc.d/rc.local:

/etc/rc.d/rc.firewall 

Configure SSH securely

I have more about setting up and using SSH on a dedicated page.

Green — everyone

Put the following directives in /etc/ssh/sshd_config to configure the SSH server. Note that many of the SSH defaults are secure, so include the following but comment out any other directives currently used.

# Only the more secure SSH2 protocol
Protocol 2
X11Forwarding yes

# Support sftp Subsystem sftp /usr/libexec/sftp-server

And for the SSH client configuration in /etc/ssh/ssh_config:

# Only the more secure SSH2 protocol
Protocol 2
# Although read "man ssh_config" first...
ForwardX11 yes
Yellow — cautious

As above, except disable direct root login. The administrator must first log in as a specific user, providing defense in depth and an audit trail, and then use the su command to elevate privileges. /etc/ssh/sshd_config

/etc/ssh/sshd_config

# Only the more secure SSH2 protocol
Protocol 2
X11Forwarding yes

# Do not allow root login -- first login
# as an ordinary user, then su to root
PermitRootLogin no
# Support sftp
Subsystem sftp /usr/libexec/sftp-server

And for the SSH client configuration in /etc/ssh/ssh_config:

# Only the more secure SSH2 protocol
Protocol 2
# Although read "man ssh_config" first...
ForwardX11 yes
Red — paranoid

Put the following directives in /etc/ssh/sshd_config. Note that many of the SSH defaults are secure, so include the following but comment out any other directives currently used in your SSH daemon configuration:


# Only the more secure SSH2 protocol
Protocol 2
# List users allowed to connect via SSH
# Also see "AllowGroups", "DenyUsers",
# and "DenyGroups" in "man sshd_config".
AllowUsers joe jane ....
# Only the strongest ciphers
Ciphers blowfish-cbc,aes256-gcm@openssh.com,aes256-cbc,aes256-ctr
# Only accept authentication via cryptographic
# challenge-response (remote client must have
# cryptographic keys)
PasswordAuthentication no
# Do not allow root login -- first login
# as an ordinary user, then su to root
PermitRootLogin no
# Support sftp Subsystem sftp /usr/libexec/sftp-server

And for the SSH client configuration in /etc/ssh/ssh_config:

# Only the more secure SSH2 protocol
Protocol 2

Hide BIND version

Green — everyone

Add the line "version ..." to the file /etc/named.conf, within the "options{...};" block:

other directives appear here...

options {
     other options appear here...
     version "VERSION NOT PROVIDED";

} ;

other directives appear here...

Otherwise a would-be attacker could figure out your BIND version with this command:
$ dig @yourserver version.bind chaos txt


Prevent trivial root console break-in (Linux only)

With some Linux distributions moving from traditional SVR4 Init to Upstart, this explanation gets complicated. See the dedicated page on how this exploit works and how to prevent it. The very short version is:

On a traditional init based system (e.g., RHEL/CentOS 5):
Add the following line to the file /etc/inittab right after the line referencing /etc/rc.d/rc.sysinit

ss:S:respawn:/sbin/sulogin

On an upstart based system (e.g., RHEL/CentOS 6 and later):
Change a line in the file file /etc/sysconfig/init to read:

SINGLE=/sbin/sulogin

On Ubuntu: This has already been done for you!

Yellow — cautious

Reconfigure the BIOS to disable booting from media and set a BIOS password, as discussed on the Linux break-in and defense page.

Red — paranoid

Consider alarming the system case, as discussed on the Linux break-in and defense page. After all, the attacker could start by removing the battery from the motherboard.


Harden the file system

Green — everyone

Make /tmp a RAM-based filesystem. RAM is much faster than a disk, and any data stored there is truly temporary and is lost at shutdown.

Yellow — cautious

Do the above, but prevent an attacker from doing many things by making /tmp less useful to them. Make the /etc/fstab entry say:

Linux:

none /tmp tmpfs rw,noexec,nosuid,nodev,size=100000000 0 0 

OpenBSD:

swap /tmp mfs rw,noexec,nosuid,nodev,-s=128000 0 0 
Red — paranoid

Do all the above, and also use the noexec, nosuid, and nodev options on other partitions as appropriate — maybe something like this:

/varnosuid,nodev,noexec
/homenosuid,nodev
/usrnodev

Harden root authentication

Yellow — cautious

Best practice for the root account is:

Do the following. Be very careful, this is where you can lock yourself out and only be able to break in with rescue media.

Disallow direct root login on the console

Prevent root network authentication

Prevent unencrypted transmission of the root password

Limit the set of people able to attempt to become root (unneeded on OpenBSD)

At this point you could write the root password on the monitor, and ordinary users still would be unable to become root — not that this is a good idea, but root privileges now require knowledge of a privileged account's password plus knowledge of the root password.


Harden user authentication

Enforce password quality (Linux only)

Green — everyone

Linux distributions have typically tried to enforce password quality through a PAM module like pam_cracklib.so and then pam_passwdqc.so. The evolution continues with pam_pwquality.so.

However, people are generally unsatisfied with these as they don't provide the same control functions as the Windows policies.

I don't think it matters all that much. Password security is largely an illusion anyway, and it's far worse on Windows than on anything else. If you really need the exact form of control you get on Windows, then you will need to have your Linux systems do user authentication against an Active Directory server.

To do password quality control on Linux, use pam_pwquality.so. This PAM module groups characters into four classes:
   Lower-case letters
   Upper-case letters
   Digits
   Everything else

You may be happy with its default behavior, but definitely check out its manual page. You can adjust its rules by adding parameters to its line in the PAM file, although a better solution would be to put your configuration in /etc/security/pwquality.conf so that every program handling password changes applies the same rules.

This will take a lot of experimentation, and do remember that it doesn't work the way that Windows does. Be happy with that.

Yellow — cautious

Use stricter rules for pam_pwquality.so.

Red — paranoid

You know, if you really want to take full advantage of the security offered by the cryptographic hashes used to store password information, you need to consider the fact that English text contains about 1.2 bits of entropy per character.

Of course, these days an MD5 hash is considered to be very weak, but its 128-bit output would require 128/1.2 = 106.66 characters of English prose to fully utilize its limited security. There is no way a user can accurately type over a hundred characters without seeing what they're typing. With newer distributions using SHA-2-512 by default, 512/1.2 = 426.67 password characters is even more preposterous.


To the Computer / Network Security Page
To the Unix / Linux Page