Original Author: Hunter Gregal
Updated By: Justin Fimlaid
***NOTICE*** To those reading this…
3/8/22: I think *most* of this information is still good but please be cognizant of the Ubuntu version numbers. There’s some great comments at the bottom about additional hardening. Please take a moment to read those intelligent comments. – Justin
A key concept in security is ensuring that your server’s operating system is adequately secured, or “hardened”. All too often server administrators will focus on security at their application layer such as a webserver with dynamic content. While this is absolutely important, one must not forget to harden their server’s operating system to prevent against initial exploitation and consequently post-exploitation attacks such as privilege escalation. Operating system hardening should be implemented before any services are hosted, whether the system be in a production or development environment. The following tips and tricks are some easy ways to quickly harden an Ubuntu server.
Keep System Up-To-Date
An extremely crucial part of hardening any system is to ensure that it is always kept up-to-date. Doing this will keep any known bugs or vulnerabilities patched if one exists. The following commands are ways to update an Ubuntu system:
apt-get update && apt-get upgrade
Accounts
A good place to start when dealing with any operating system’s security is to ensure that user accounts are locked down.
Ensure Only root Has UID of 0
Accounts that have a UID set to 0 have the highest access to a system. In most cases, this should only be the “root” account. Using the below command will list all accounts with a UID of 0:
awk -F: '($3=="0"){print}' /etc/passwd
Check for Accounts with Empty Passwords
Accounts that have no password essentially have no security. The command below will print all accounts that have an empty password:
cat /etc/shadow | awk -F: '($2==""){print $1}'
Lock Accounts
In addition, you can use the command below to lock any accounts (prepends a ! to the user’s password hash):
passwd -l accountName
Adding New User Accounts
It is best practice to keep the use of the root account to a minimum. To do this, add a new account that will be primarily used with the command below:
adduser accountName
This will automatically create a user with the default configuration defined in ‘/etc/skel’.
Sudo Configuration
The Sudo package allows a regular user to run commands in an elevated context. This means a regular user can run commands normally restricted to the root account. Often, this is the ideal way of making system configurations or running elevated commands; not by using the root account. The configuration file for Sudo is in /etc/sudoers, however it can only be edited by using the “visudo” command. There are many different configuration options for that limit the use of Sudo to certain users, groups, Ips, and commands. The general configuration format is below:
%www ALL=(ALL)NOPASSWD:/bin/cat,/bin/ls
%www – All users of the www group
ALL= – From any Host/IP
(ALL) – can run as any user
NOPASSWD – No password required (omit to require a password)
:/bin/cat,/bin/ls – Commands able to run as sudo. In this case, “cat” and “ls”
To run any elevated command, simply place “sudo” in front of it as a properly configured user.
IpTables
IpTables are essentially your operating system’s firewall. IpTables are extremely powerful in controlling the network traffic going into and out of your server. While I will give some very basic example configurations below, it is recommended that any person looking into hardening their Ubuntu OS do research into IpTables implementation.
Running the commands below will configured your box to allow inbound connections only on ports 80, 22, and the loopback interface and drop all other packets (configure to your own server’s needs):
iptables -A INPUT -p tcp -m tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -I lo -j ACCEPT
iptables -A INPUT -j DROP
(Or use iptables -P INPUT DROP
to automatically drop all packets without a rule)
SSH
It goes without saying that all services hosted on your server should be adequately configured and locked down; however since SSH is almost always going to be running on your server, it is essential to lock it down as much as possible. The SSH service configuration file can be found at ‘/etc/ssh/sshd_config’.
Disable root Login
This configuration will limit SSH only to users other than root. Find and ensure the line for “PermitRootLogin” exists and looks like the one below:
PermitRootLogin no
Allow Specific Users
This line will allow you to specify which users can log into the SSH service:
AllowUsers accountName
Change Default Port From 22
This line will specify which port to host the SSH service on. It is recommended to change this to a non-default high port number. (Remember to fix your IpTables accordingly!)
Port 22222
Disable Empty Passwords
This line ensures that no users can login with an empty password. This adds a nice layer of security if there is a user without a password set:
PermitEmptyPasswords no
Restart Service
As always, after making changes to a service be sure to restart it!
service ssh restart
Additional Tips and Tricks
In addition to the server hardening tips above, below are some useful things to remember when hardening an Ubuntu server:
Display All Current Connections, Listening Services, and Processes Handling Them
The below command can be an Ubuntu sysadmin’s best friend, it will list all current connections and listening services on a system along with the processes and PIDs for each connection:
netstat -tulpn
Display Services and Their Status
The command below will list all services on the system and their status:
service --status-all
Use grep to specify only the running services:
service --status-all | grep "[ + ]"
Check for Rootkits
The package “rkhunter” is useful for doing a quick scan of your system for any known rootkits:
apt-get install rkhunter
rkhunter -C
Common Configuration File Locations
Below are configuration file locations for just a few common services:
/etc/apache/apache2.conf #Apache 2
/etc/ssh/sshd_config #SSH Server
/etc/mysql/mysql.cnf #MySQL
/var/lib/mysql/ #This entire directory contains all of the database in MySQL
Log Locations
Below are the common default log locations:
/var/log/message — Where whole system logs or current activity logs are available.
/var/log/auth.log — Authentication logs.
/var/log/kern.log — Kernel logs.
/var/log/cron.log — Crond logs (cron job).
/var/log/maillog — Mail server logs.
/var/log/boot.log — System boot log.
/var/log/mysqld.log — MySQL database server log file.
/var/log/secure — Authentication log.
/var/log/utmp or /var/log/wtmp — Login records file.
/var/log/apt — Apt package manager logs
Hardening a server is a critical step in any server setup procedure. Any time that a new server is being brought up to host services, whether production, development, internal or external, the server’s operating system must be made as secure as possible. The tips and tricks above along with the recommendations are some basic ways to enhance your Ubuntu server’s security. This blog post is meant to give a starting point when hardening a server and should be used along with best security practices and standards at your company.
If you guys have any additional tips for hardening an Ubuntu Server, feel free to comment!
I would also add UseRoaming no in your ssh configuration and disable IPv6 if you are not using it. It leaves massive holes in systems without people realizing and locking down users ability to execute code scripts outside of designated areas.
I would install clamAV and Lynis. Lynis gives you great auditing capabilites to create a baseline for security. I would also remove CUPS, the print server. There are several CVE’s associated with various versions, and generally, people don’t print from their server. Great writeup!
If you are in and enterprise and must also pass audits, a great way to do that is to use a configuration management system such as Ansible and apply a CIS standards-based playbook against the servers on a regular basis to ensure compliance. This will also lock down hundreds more items than are listed here that are all important to real server security.
You change the ssh port to 2222, but don’t add the correct iptables rule. 😉
iptables -A INPUT -p tcp -m tcp –dport 2222 -m state –state NEW,ESTABLISHED -j ACCEPT
And better add
iptables -A INPUT -p tcp -m tcp –dport 443 -m state –state NEW,ESTABLISHED -j ACCEPT
443 is ssl port
Install fail2ban to prevent unusual ips from loggin in
If you are using central authentication, you should also consider using something like pam-ccreds and/or libnss-db to keep cached copies of critical accounts. That way you can still get in, even if contact with the central auth server is broken.
one should add the following rule:
iptables -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT
I wasn’t able to DNS-resolve any hosts anymore after adding the -j DROP-line.
Besides, many thanks for the post!
Use grep to specify only the running services:
service –status-all | grep “[ + ]”
^ The above command is wrong and won’t work for grep. You need to escape brackets like this:
service –status-all | grep “\[ + \]”
Highly recommend setting up ufw to prevent SYN FLOOD attacks and adding fail2ban + configuring some jails for bad actors scanning or trying to ssh with wrong passwords.
You may also want to use key auth instead of passwords in sshd_config
“`
PasswordAuthentication no
PubkeyAuthentication yes
“`