Ubuntu Server Hardening
The Advanced Guide To Server Security¶
Last updated: May 2022. For advanced users. Solid tech skills required.
Disclaimer
No system is safe. This is the second chapter on server security. While it presents more advanced measures to protect your Ubuntu server from most immediate threats, any skilled hacker or organisation with sufficient resources will probably find a way into the system.
Sudo access¶
Privileged access should be limited to users of a specific group, as detailed below.
Show me the step-by-step guide
Create a group called sudousers
, and add both users gofossroot
and gofossadmin
(adjust user names according to your own setup):
sudo groupadd sudousers
sudo usermod -a -G sudousers gofossroot
sudo usermod -a -G sudousers gofossadmin
Backup the sudoers
configuration file. If something goes wrong, you'll be able to recover the initial settings:
sudo cp --archive /etc/sudoers /etc/sudoers-COPY-$(date +"%Y%m%d%H%M%S")
Open the configuration file:
sudo vi /etc/sudoers
Add the following line, if it's not already there:
%sudousers ALL=(ALL:ALL) ALL
Save and close the file (:wq!
). Finally, limit access to elevated privileges to the sudousers
group:
sudo dpkg-statoverride --update --add root sudousers 4750 /bin/su
Check permissions with the following command, the terminal should display sudousers
:
ls -lh /bin/su
Show me the 1-minute summary video
/proc directory¶
The /proc
directory contains potentially sensitive information about processes. By default, all users can access this directory. Follow the instructions below to continue hardening your server and keep sensitive data hidden from unauthorised users or programs.
Show me the step-by-step guide
Back up the fstab
configuration file. If something goes wrong, you'll be able to recover the initial settings:
sudo cp --preserve /etc/fstab /etc/fstab-COPY-$(date +"%Y%m%d%H%M%S")
Open the configuration file:
sudo vi /etc/fstab
Hide process information by adding the following line at the end of the file:
proc /proc proc defaults,hidepid=2 0 0
Save and close the file (:wq!
). Finally, remount the /proc
directory:
sudo mount -o remount,hidepid=2 /proc
Show me the 1-minute summary video
PAM user authentication¶
By default, users are free to choose any password. Read on below for more details on how to enforce strong passwords and define quality requirements such as:
- the maximum number of days a password can be used
- the minimum number of days before a password can be changed
- the minimum password length
- the number of upper and lower case characters as well as digits to be used
Show me the step-by-step guide
Configure account parameters¶
Back up the login.defs
configuration file. If something goes wrong, you'll be able to recover the initial settings:
sudo cp --preserve /etc/login.defs /etc/login.defs-COPY-$(date +"%Y%m%d%H%M%S")
Open the configuration file:
sudo vi /etc/login.defs
Modify or add the following parameters:
PASS_MAX_DAYS 365
PASS_MIN_DAYS 1
PASS_WARN_AGE 30
SHA_CRYPT_MIN_ROUNDS 1000000
SHA_CRYPT_MAX_ROUNDS 1000000
Save and close the file (:wq!
).
Let's apply the same settings to administrator users gofossroot
and gofossadmin
, which were created before password rules were hardened (adjust usernames according to your own setup):
sudo chage -m 1 -M 365 -W 30 gofossroot
sudo chage -m 1 -M 365 -W 30 gofossadmin
Make sure all changes were correctly applied:
sudo chage -l gofossroot
sudo chage -l gofossadmin
Some additional information on those settings:
Setting | Description |
---|---|
PASS_MAX_DAYS | Maximum number of days a password may be used. |
PASS_MIN_DAYS | Minimum number of days allowed between password changes. |
PASS_WARN_AGE | Number of days a warning is given before a password expires. |
SHA_CRYPT_MIN_ROUNDS & SHA_CRYPT_MAX_ROUNDS | By default, Linux stores the administrator password using a single, salted SHA-512 hash. To strengthen the password, use multiple rounds of a hash. |
Configure PAM¶
Linux Pluggable Authentication Modules (PAM) is a powerful suite to manage user authentication. Install the following PAM module, which allows to strength-check passwords:
sudo apt install libpam-cracklib
Back up the pam.d
configuration file. If something goes wrong, you'll be able to recover the initial settings:
sudo cp --archive /etc/pam.d/common-password /etc/pam.d/common-password-COPY-$(date +"%Y%m%d%H%M%S")
Open the configuration file:
sudo vi /etc/pam.d/common-password
Modify or add the following parameters:
password requisite pam_cracklib.so retry=3 minlen=12 ucredit=-1 lcredit=-1 dcredit=-1 difok=3 gecoschec
In the same file, add the shadow
option as well as an increased number of rounds
in the following line:
password [success=1 default=ignore] pam_unix.so obscure use_authtok try_first_pass sha512 shadow rounds=1000000
Save and close the file (:wq!
).
Some additional information on those settings:
Setting | Description |
---|---|
retry = 3 | Prompt users 3 times before returning an error. |
minlen = 10 | Minimum password length. |
ucredit = -1 | Password must have at least one upper case letter. |
lcredit = -1 | Password must have at least one lower case letter. |
dcredit = -1 | Password must have at least one digit. |
difok = 3 | At least 3 characters from the new password cannot have been used in the old password. |
gecoschec | Do not allow passwords with the account's name in it. |
shadow rounds=1000000 | By default, the pam_unix module stores the administrator password using a single, salted SHA-512 hash. To strengthen the password, Linux PAM can use multiple rounds of a hash. |
Show me the 2-minute summary video
sysctl network security¶
The system administration command sysctl
allows to fine tune the kernel and can be used to improve network security. More details below.
Show me the step-by-step guide
Back up the sysctl
configuration file. If something goes wrong, you'll be able to recover the initial settings:
sudo cp --archive /etc/sysctl.conf /etc/sysctl.conf-COPY-$(date +"%Y%m%d%H%M%S")
Open the configuration file:
sudo vi /etc/sysctl.conf
Delete the content by typing :%d
. Then enter or copy/paste the following content:
# IP Spoofing protection
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Ignore ICMP broadcast requests
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Disable source packet routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
# Block SYN attacks
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
# Log Martians
net.ipv4.conf.all.log_martians = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Ignore ICMP redirects
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# Ignore Directed pings
net.ipv4.icmp_echo_ignore_all = 1
Save and close the file (:wq!
), and load the new settings:
sudo sysctl -p
Some additional information on those security settings:
Measure | Description |
---|---|
Enable IP spoofing protection | Protect against IP spoofing where attackers disguise their IP, typically during Denial of Service (DoS) attacks. |
Ignore ICMP broadcast requests | Avoid that the server participates in a Smurf attack. |
Ignore ICMP redirects | Protect against forged ICMP redirect packets used by attackers to cause a Denial of Service (DoS) attack. |
Disable source packet routing | Protect against source routed packets used by attackers to obscure their identity and location. |
Block SYN attacks | Protect against SYN attacks, a form of Denial of Service (DoS) attack. |
Log martians | Protect against martian packets. These are spoofed packets with a source address which is obviously wrong. They can be used during Denial of Service (DoS) attacks. |
Ignore directed pings | The ping command can be used to check the connection status with your server. But it can also be misused to perform attacks. |
Show me the 1-minute summary video
LMD & ClamAV¶
Linux Malware Detect (LMD) and ClamAV are open source antivirus and malware scanner solutions. Follow the instructions below to install and configure them on your server.
Show me the step-by-step guide
Malware scanner (LMD)¶
Install LMD using the following commands:
sudo apt install wget
sudo wget http://www.rfxn.com/downloads/maldetect-current.tar.gz
sudo tar -xvf maldetect-current.tar.gz
cd maldetect-1.6.4
sudo ./install.sh
Back up the maldet
configuration file. If something goes wrong, you'll be able to recover the initial settings:
sudo cp --archive /usr/local/maldetect/conf.maldet /usr/local/maldetect/conf.maldet-COPY-$(date +"%Y%m%d%H%M%S")
Open the configuration file:
sudo vi /usr/local/maldetect/conf.maldet
Modify or add the following parameters (adjust the administrator user gofossadmin
according to your own setup):
# send malware inspection results to local system administrator gofossadmin (adjust accordingly) in /var/mail/gofossadmin
email_alert="1"
email_addr="gofossadmin@localhost"
# move to quarantine & alert if malware is detected
quarantine_hits="1"
# don't automatically delete clean string-based malware injections (in case of false positives, avoid deleting files)
quarantine_clean="0"
# allow suspending users hit by malware
quarantine_suspend_user="1"
#use ClamAVs scanner engine (faster scans)
scan_clamscan="1"
#scan root owned files
scan_ignore_root="0"
Save and close the file (:wq!
). Update LMD to the latest version and download the most recent malware definitions:
sudo maldet --update-ver
sudo maldet --update
Antivirus (ClamAV)¶
Install ClamAV with the following command:
sudo apt install clamav
Check if the software was successfully installed:
clamscan --version
Update the virus signature database:
sudo systemctl stop clamav-freshclam
sudo freshclam
sudo systemctl start clamav-freshclam
Enable ClamAV to be automatically launched after each reboot:
sudo systemctl enable clamav-freshclam
Test LMD and ClamAV¶
We'll use dummy malware provided by the European Expert Group for IT Security (EICAR) to test the malware scanner and antivirus. Download the files as follows:
cd /var/www/html
sudo wget http://www.eicar.org/download/eicar.com
sudo wget http://www.eicar.org/download/eicar.com.txt
sudo wget http://www.eicar.org/download/eicar_com.zip
sudo wget http://www.eicar.org/download/eicarcom2.zip
Use ClamAV to recursively scan the directory /var/www/html
and all its subdirectories for viruses:
sudo clamscan --recursive --infected /var/www/html
The terminal should prompt something similar to:
/var/www/html/eicar_com.zip: Win.Test.EICAR_HDB-1 FOUND
/var/www/html/eicar.com: Win.Test.EICAR_HDB-1 FOUND
/var/www/html/eicarcom2.zip: Win.Test.EICAR_HDB-1 FOUND
/var/www/html/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND
----------- SCAN SUMMARY -----------
Known viruses: 6880642
Engine version: 0.102.2
Scanned directories: 1
Scanned files: 5
Infected files: 4
Data scanned: 0.01 MB
Data read: 0.01 MB (ratio 1.00:1)
Time: 54.632 sec (0 m 54 s)
Next, use LMD to scan the same directory for malware:
sudo maldet --scan-all /var/www/html
The output should contain a scan ID, something similar to 200510-1954.2127
(adjust accordingly). Inspect the detailed report with:
sudo maldet --report 200510-1954.2127
A list of all scan reports can be accessed with:
sudo maldet -e list
Finally, remove all quarantined files:
sudo ls /usr/local/maldetect/quarantine/
sudo rm -rf /usr/local/maldetect/quarantine/*
Schedule LMD scans¶
The malware scanner LMD is configured to run a daily cron job (/etc/cron.daily/maldet
) which updates the malware registry and scans all home directories. That should be sufficient for most use cases. To keep the server load down, disable real time monitoring to avoid scans running every 10 minutes:
sudo rm /etc/cron.d/maldet_pub
sudo maldet -k
Schedule ClamAV scans¶
The virus signature database is updated by the freshclam
service. By default, it fetches updates every hour, you can change the frequency in the /etc/clamav/freshclam.conf
file and restart the service with sudo service clamav-freshclam restart
.
To schedule antivirus scans, create an empty log file:
sudo touch /var/log/clamav/clamscan.log
Create a cron job to scan for viruses every day:
sudo vi /etc/cron.daily/clamav
Add the following content:
#!/bin/sh
MYLOG=/var/log/clamav/clamscan.log
echo "Scanning for viruses at `date`" >> $MYLOG
clamscan --recursive --infected --max-filesize=100M --max-scansize=100M --exclude=/boot / >> $MYLOG 2>&1
Save and close the file (:wq!
). Now, make the script executable:
sudo chmod +x /etc/cron.daily/clamav
Note that we used the following options to run clamscan
in the script, which should be adapted to your own needs:
Parameter | Description |
---|---|
--recursive | Recursively scan directories and sub-directories for viruses. |
--infected | Only print infected files in the scan report, instead of all scanned files. |
--max-filesize=100M , --max-scansize=100M | Scan files with a file size of up to 100 MB. By default, ClamAV doesn't scan files larger than 20 MB. |
--exclude=/boot | In this example, we exclude the directory /boot from the scan. Make sure to adjust this to your own setup, the option can also be used multiple times to exclude multiple directories. |
/ | Directory which ClamAV is supposed to scan for viruses. In this example, we want to scan the entire root folder / . Of course, you can adapt the target directory according to your own needs. |
Test the cron job. Be patient, depending on the size of the target directories the scan can take a while:
sudo bash /etc/cron.daily/clamav
sudo cat /var/log/clamav/clamscan.log
The terminal output should look something like:
----------- SCAN SUMMARY -----------
Infected files: 0
Time: 54.052 sec (0 m 54 s)
Start Date: 2021:05:22 21:05:29
End Date: 2021:05:22 21:06:23
Show me the 4-minute summary video
File and directory permissions¶
Read on below to find out how to restrict unauthorised access to the system files.
Show me the step-by-step guide
sudo chmod 600 /etc/crontab
sudo chmod 600 /etc/ssh/sshd_config
sudo chmod 700 /etc/cron.d
sudo chmod 700 /etc/cron.daily
sudo chmod 700 /etc/cron.hourly
sudo chmod 700 /etc/cron.weekly
sudo chmod 700 /etc/cron.monthly
sudo chmod 750 /home/gofossroot
sudo chmod 750 /home/gofossadmin
Show me the 1-minute summary video
Tell me more about Linux permissions
umask restricts user access to newly created files or directories. There are three user classes:
User Class | Description |
---|---|
User | The file's or directory's owner. |
Group | Users belonging to the file's or directory's group. |
Others | Users who are neither owner nor member of the file's or directory's group. |
And there are three access restrictions:
Access restriction | Description | Decimal value |
---|---|---|
Read ( r ) | Read or view the file or directory. | 4 |
Write ( w ) | Write to, edit or modify the file or directory. | 2 |
Execute ( x ) | Execute the file or directory. | 1 |
umask
restricts access to newly created files or directories by summing up those three decimal values:
umask | Value | Restrictions |
---|---|---|
--- | 0 = 0 + 0 + 0 | Can read, write & execute. |
--x | 1 = 0 + 0 + 1 | Can read & write, but not execute. |
-w- | 2 = 0 + 2 + 0 | Can read & execute, but not write. |
-wx | 3 = 0 + 2 + 1 | Can read, but not write or execute. |
r-- | 4 = 4 + 0 + 0 | Can write & execute, but not read. |
r-x | 5 = 4 + 0 + 1 | Can write, but not read or execute. |
rw- | 6 = 4 + 2 + 0 | Can execute, but not read or write. |
rwx | 7 = 4 + 2 + 1 | Can't read, write or execute. |
umask
consists of three values, one for each user class. For example, changing umask
from 022
to 027
prevents "others" from reading, writing or executing files and directories:
Umask | User restrictions | Group restrictions | Others restrictions | Resulting permissions |
---|---|---|---|---|
022 | --- | -w- | -w- | • The file's or directory's owner can read, write & execute. • Members of the file's or directory's group can read and execute, but not write. • Users who are neither owner nor member of the file's or directory's group can read and execute, but not write. • In other words: the file's or directory's owner has full access, the group and others can only read and execute it. |
027 | --- | -w- | rwx | • The file's or directory's owner can read, write & execute. • Members of the file's or directory's group can read and execute, but not write. • Users who are neither owner nor member of the file's or directory's group can't read, write or execute it. • In other words: the file's or directory's owner has full access, the group can only read and execute it, and others don't have access. |
Note that throughout this guide, the chmod
command is often used to define permissions for files or directories. Contrary to umask
, which sets the default restrictions for newly created files or directories, the chmod
command sets permissions for existing files or directories. As such, the values between umask
and chmod
are somewhat symmetrical.
Core dump¶
A core dump is a file containing a program's memory when it crashes. That's useful for debugging purposes, but can leak sensitive data. It's safe to disable if you don't do troubleshooting. More details below.
Show me the step-by-step guide
Backup the configuration files:
sudo cp --archive /etc/security/limits.conf /etc/security/limits.conf-COPY-$(date +"%Y%m%d%H%M%S")
sudo cp --archive /etc/sysctl.conf /etc/sysctl.conf-COPY-$(date +"%Y%m%d%H%M%S")
Open the first configuration file:
sudo vi /etc/security/limits.conf
Add the following lines at the end:
* soft core 0
* hard core 0
Save and close the file (:wq!
).
Open the second configuration file:
sudo vi /etc/sysctl.conf
Add the following lines at the end:
# Disable coredumps
fs.suid_dumpable=0
Save and close the file (:wq!
). Finally, apply the changes:
sudo sysctl -p
Show me the 1-minute summary video
Kernel modules¶
The Linux kernel is the core of the operating system. It controls the hardware, the memory, tasks and processes, and so on. Kernel modules are pieces of code that extend the kernel's functionality, for example to access new hardware. Having said that, kernel modules can also be misused to load malicious software or gain unauthorised access to the server. To avoid this, disallow the loading of unused kernel modules, as shown below.
Show me the step-by-step guide
Backup the configuration file:
sudo cp --archive /etc/modprobe.d/blacklist.conf /etc/modprobe.d/blacklist.conf-COPY-$(date +"%Y%m%d%H%M%S")
Open the configuration file:
sudo vi /etc/modprobe.d/blacklist.conf
Add the following lines at the end:
# Instruct modprobe to force inactive modules to always fail loading
install cramfs /bin/false
install freevxfs /bin/false
install hfs /bin/false
install hfsplus /bin/false
install jffs2 /bin/false
install udf /bin/false
Save and close the file (:wq!
).