Linux server security tips
Securing your Linux server is important to protect your data, intellectual property, and time, from the hands of crackers (hackers). The system administrator is responsible for security of the Linux box.
Step 1: Update your package list and upgrade your OS
Software updates and patches are often distributed to fix security vulnerabilities as they are discovered. Running outdated software puts you at risk as soon as the details of the vulnerability are published. For that reason, it is vital to make sure your packages and OS are constantly updated and as secure as they can be.
CentOS:
yum update && yum upgrade
Debian / Ubuntu:
apt-get update && apt-get upgrade
The update part updates your package list, and the upgrade part actually downloads and installs them.
To do this periodically, you can install the yum-cron (CentOS) or unattended-upgrades (Debian / Ubuntu) package.
CentOS:
yum -y install yum-cron
Debian / Ubuntu:
apt-get install unattended-upgrades
In the package’s config file, located at /etc/apt/apt.conf.d/50unattended-upgrades, you can enable or disable automatic updates for certain groups of packages. For example, you can just get security patches automatically by uncommenting “${distro_id}:${distro_codename}-security“; in the config file.
Step 2: Remove unnecessary packages
Packages that you do not need are a useless security liability on your system. They are one extra entry point for attacks that you can do without. To keep your server as lean as possible, you can either manually check through a list of packages and delete anything you do not need, or use a tool that checks for you.
The manual method:
CentOS:
yum autoremove
Debian / Ubuntu:
apt-get autoremove
Step 3: Verify no accounts have empty passwords
Accounts without passwords are vulnerable because the only thing a hacker that slipped through your defenses would need to do is key ‘enter’ along with the username, and they’d be in.
Empty passwords are easily detected; just run
awk -F: '($2 == "") {print}' /etc/shadow
This checks the whether the second element (encrypted password) is blank in your shadow file, and if it is it returns the username so you can go and give them a strong password.
To prevent this from happening again, you should set password rules for users.
Step 4: Set password rules
Type the following command to install libpam_cracklib on an Ubuntu or Debian Linux based system:
apt-get install libpam-cracklib
You need to edit the file /etc/pam.d/common-password, enter:
cp /etc/pam.d/common-password /root/ nano /etc/pam.d/common-password
Now you can force users to have strong passwords that contain complex characters including lowercase, digits, uppercase, spacial characters and punctuation. Locate the line:
password requisite pam_cracklib.so retry=3 minlen=8 difok=3
And update it as follows:
password requisite pam_cracklib.so retry=3 minlen=16 difok=3 ucredit=-1 lcredit=-2 dcredit=-2 ocredit=-2
Where,
- retry=3: Prompt user at most 3 times before returning with error. The default is 1.
- minlen=16: The minimum acceptable size for the new password.
- difok=3: This argument will change the default of 5 for the number of character changes in the new password that differentiate it from the old password.
- ucredit=-1: The new password must contain at least 1 uppercase characters.
- lcredit=-2: The new password must contain at least 2 lowercase characters.
- dcredit=-2: The new password must contain at least 2 digits.
- ocredit=-2: The new password must contain at least 2 symbols.
Step 5: Set password expiration in login.defs
To ensure your users are regularly setting strong, unique passwords, now make sure to configure how often passwords expire.
You need to edit the file
nano /etc/login.defs
Is where a big chunk of the password configuration rules live. Open it in a text editor, and look for the password aging control line. You will see three parameters:
- PASS_MAX_DAYS: Maximum number of days a password may be used. If the password is older than this, a password change will be forced.
- PASS_MIN_DAYS: Minimum number of days allowed between password changes. Any password changes attempted sooner than this will be rejected
- PASS_WARN_AGE: Number of days warning given before a password expires. A zero means warning is given only upon the day of expiration, a negative value means no warning is given. If not specified, no warning will be provided.
It is recommended that password changes should be enforced at least every 90 days because if old backups are lost or misfiled you would not want the password file data on them to be still valid and able to be used to get into your server.
Step 6: Check which services are started at boot time
Until you check, you can not be sure that you do not have malicious services starting at boot time and running in the background. This is easy to fix by installing sysv-rc-conf:
apt-get install sysv-rc-conf
Check which services are started at boot time by inputting the following in a terminal:
sysv-rc-conf --list | grep '3:on'
This will highlight the names of every service that starts at boot time.
Now, you can disable a service by typing:
systemctl disable <service>
Step 7: Detect all world-writable files
World-writable files are modifiable by any user on the system. If you have files that only root or an admin should be able to access that are world-writable, you’re at risk.
Display a list of world-writable files with:
find / -xdev -type d \( -perm -0002 -a ! -perm -1000 \) -print
If anything should not be accessible to every single user, make sure to go in and modify the permissions.
Step 8: Configure iptables to block common attacks
Iptables is as powerful as it is complex. It deserves deeper exploration than it can be given in this article, but here are a few example commands you can use to block common attacks:
#!/bin/sh IPTABLES="/sbin/iptables" echo " * flushing old rules" # flush the old rules ${IPTABLES} -F # clear all filter chains #/sbin/iptables -F -t nat ${IPTABLES} -F -t mangle ${IPTABLES} -X #/sbin/iptables -X -t nat ${IPTABLES} -X -t mangle echo " * setting default policies" #set default policy ${IPTABLES} -P INPUT DROP # default action DROP - blocking package ${IPTABLES} -P OUTPUT ACCEPT # allow all outgoing packets #create new chain (BAD_PACKETS) ${IPTABLES} -N BAD_PACKETS echo " * BLACKLIST" ${IPTABLES} -N BANNED #Blocked users ${IPTABLES} -A INPUT -j BANNED #jump to BAD_PACKETS ${IPTABLES} -A INPUT -j BAD_PACKETS echo " * allowing loopback devices" #allow the loopback ${IPTABLES} -A INPUT -i lo -j ACCEPT # to all the packets that belong to an established connection, the terminal applies the action of ACCEPT - skip ${IPTABLES} -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT ${IPTABLES} -A INPUT -m state --state NEW -p tcp --dport 139 -j ACCEPT ${IPTABLES} -A INPUT -m state --state NEW -p tcp --dport 445 -j ACCEPT # you can allow the ports to which such a check is not necessary. echo " * allowing ssh on port 22" ${IPTABLES} -A INPUT -m state --state NEW -p tcp --dport 22 -j ACCEPT echo " * allowing http on port 80" ${IPTABLES} -A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT echo " * allowing https on port 443" ${IPTABLES} -A INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT # FTP #/sbin/iptables -A INPUT -m state --state NEW -p tcp --dport ftp -j ACCEPT #/sbin/iptables -A INPUT -m state --state NEW -p tcp --sport ftp-data -j ACCEPT #/sbin/iptables -A INPUT -m state --state NEW -p tcp --sport 1500:1505 -j ACCEPT ############################################################################ # mail server /sbin/iptables -A INPUT -m state --state NEW -p tcp --dport 25 -j ACCEPT #/sbin/iptables -A INPUT -m state --state NEW -p tcp --dport 110 -j ACCEPT #/sbin/iptables -A INPUT -m state --state NEW -p tcp --dport 143 -j ACCEPT #/sbin/iptables -A INPUT -m state --state NEW -p tcp --dport 993 -j ACCEPT #/sbin/iptables -A INPUT -m state --state NEW -p tcp --dport 995 -j ACCEPT # allow DHCP echo " * allowing DHCP on port 67" /sbin/iptables -A INPUT -p UDP --dport 68 --sport 67 -j ACCEPT #allow ICMP replies from specified hosts (ping) echo " * allow ICMP replies from specified hosts" /sbin/iptables -A INPUT -p ICMP --icmp-type 8 -j ACCEPT #allow DNS # hex string # MX - 00 0F (5 queries / 60 seconds) # AAAA - 00 1C (2 queries / 10 seconds) # A - 00 01 (100 queries / 10 seconds) # PTR - 00 0C (50 queries / 10 seconds) # CNAME - 00 05 (100 queries / 10 seconds) # NS - 00 02 (10 queries / 60 seconds) # SOA - 00 06 (5 queries / 60 seconds) # SRV - 00 21 (5 quries / 60 seconds) /sbin/iptables -A INPUT -p udp --dport 53 -m state --state NEW -m string --algo kmp --hex-string "|00 0F 00 01|" -m recent --set --name MXFLOOD --rsource /sbin/iptables -A INPUT -p udp --dport 53 -m state --state NEW -m string --algo kmp --hex-string "|00 0F 00 01|" -m recent --update --seconds 60 --hitcount 5 --rttl --name MXFLOOD -j DROP /sbin/iptables -A INPUT -p udp --dport 53 -m string --algo kmp --hex-string "|00 0F 00 01|" -j ACCEPT /sbin/iptables -A INPUT -p udp --dport 53 -m state --state NEW -m string --algo kmp --hex-string "|00 1C 00 01|" -m recent --set --name AAAAFLOOD --rsource /sbin/iptables -A INPUT -p udp --dport 53 -m state --state NEW -m string --algo kmp --hex-string "|00 1C 00 01|" -m recent --update --seconds 10 --hitcount 2 --rttl --name AAAAFLOOD -j DROP /sbin/iptables -A INPUT -p udp --dport 53 -m string --algo kmp --hex-string "|00 1C 00 01|" -j ACCEPT /sbin/iptables -A INPUT -p udp --dport 53 -m state --state NEW -m string --algo kmp --hex-string "|00 01 00 01|" -m recent --set --name AFLOOD --rsource /sbin/iptables -A INPUT -p udp --dport 53 -m state --state NEW -m string --algo kmp --hex-string "|00 01 00 01|" -m recent --update --seconds 10 --hitcount 20 --rttl --name AFLOOD -j DROP /sbin/iptables -A INPUT -p udp --dport 53 -m string --algo kmp --hex-string "|00 01 00 01|" -j ACCEPT /sbin/iptables -A INPUT -p udp --dport 53 -m state --state NEW -m string --algo kmp --hex-string "|00 05 00 01|" -m recent --set --name CNAMEFLOOD --rsource /sbin/iptables -A INPUT -p udp --dport 53 -m state --state NEW -m string --algo kmp --hex-string "|00 05 00 01|" -m recent --update --seconds 10 --hitcount 20 --rttl --name CNAMEFLOOD -j DROP /sbin/iptables -A INPUT -p udp --dport 53 -m string --algo kmp --hex-string "|00 05 00 01|" -j ACCEPT /sbin/iptables -A INPUT -p udp --dport 53 -m state --state NEW -m string --algo kmp --hex-string "|00 06 00 01|" -m recent --set --name SOAFLOOD --rsource /sbin/iptables -A INPUT -p udp --dport 53 -m state --state NEW -m string --algo kmp --hex-string "|00 06 00 01|" -m recent --update --seconds 60 --hitcount 5 --rttl --name SOAFLOOD -j DROP /sbin/iptables -A INPUT -p udp --dport 53 -m string --algo kmp --hex-string "|00 06 00 01|" -j ACCEPT # log #/sbin/iptables -A INPUT -j LOG --log-prefix "INPUT DROP: " #drop BAD_PACKETS /sbin/iptables -A BAD_PACKETS -p TCP ! --syn -m state --state NEW -j DROP /sbin/iptables -A BAD_PACKETS -p TCP --tcp-flags ALL ALL -j DROP /sbin/iptables -A BAD_PACKETS -p TCP --tcp-flags ALL NONE -j DROP /sbin/iptables -A BAD_PACKETS -p TCP --tcp-flags ALL SYN \-m state --state ESTABLISHED -j DROP /sbin/iptables -A BAD_PACKETS -p ICMP --fragment -j DROP /sbin/iptables -A BAD_PACKETS -m state --state INVALID -j DROP /sbin/iptables -A BAD_PACKETS -d 255.255.255.255 -j DROP /sbin/iptables -A BAD_PACKETS -j RETURN #drop BANNED #/sbin/iptables -A BANNED -s 146.0.42.124 -j DROP echo "Rules written."
Make sure to read the iptables manual (man iptables) for more information on blocking connections from particular IP addresses or to certain hosts.
Step 9: Secure any Apache servers
Apache servers make for a wonderfully predictable entry point for attackers — you only have to check the number of Apache vulnerabilities that have surfaced over the years to be wary about the security of yours.
Open your Apache config file — located at
nano /etc/apache2/apache2/conf
and modify the defaults to reflect the following lines:
ServerTokens Prod ServerSignature Off Header always unset X-Powered-By
These three lines above prevent Apache from broadcasting its version number and other identifiable details, which makes it harder for attackers to exploit known vulnerabilities.
TraceEnable Off
Turning off TRACE protects you against known cross-site tracking vulnerabilities.
Step 10: Configure SSH securely
Even though SSH may have been compromised by the U.S. government in some roundabout way, it is still the standard protocol for controlling a server remotely. One of the biggest dangers with SSH — especially for large organizations with thousands of servers — is managing SSH keys. If an attacker gains access to your servers through a misplaced SSH key, you want to be sure that you minimize the damage they can do, or lock them out entirely.
To achieve this, add the restrictions below to your SSH config file, located at /etc/ssh/ssh_config:
- PermitRootLogin no # disallows root access via SSH
- AllowUsers [username] # limits SSH access to the stated users
- IgnoreRhosts yes # disallows SSH from trusting a host based only on its IP
- HostbasedAuthentication no # as above
- PermitEmptyPasswords no # prevents users from logging into SSH with an empty password, if set as such
- X11Forwarding no # stops the possiblity of the server sending commands back to the client
- MaxAuthTries 5 # drops the SSH connection after 5 failed authorization attempts
- Ciphers aes128-ctr,aes192-ctr,aes256-ctr # disable weak ciphers
- UsePAM yes # disables password authentication and defers authorization to the key-based PAM
- ClientAliveInterval 900 # logs out idle users after 15 minutes
- ClientAliveCountMax 0 # how many times the server checks whether the session is active before dropping
Step 11: Disable telnet
apt-get remove telnet
Step 12: Configure sysctl securely
Your default sysctl settings may leave you open to syn flood attacks and IP spoofing, or may not log suspicious packages.
To harden your sysctl settings, open
nano /etc/sysctl.conf
in a text editor, and do the following:
Disable IP Forwarding by setting the net.ipv4.ip_forward parameter to 0
Disable the Send Packet Redirects by setting the net.ipv4.conf.all.send_redirects and net.ipv4.conf.default.send_redirects parameters to 0
Disable ICMP Redirect Acceptance by setting the net.ipv4.conf.all.accept_redirects and net.ipv4.conf.default.accept_redirects parameters to 0
Enable Bad Error Message Protection by setting the net.ipv4.icmp_ignore_bogus_error_responses parameter to 1
Step 13: Lock user accounts after failed attempts with Fail2Ban
Fail2Ban helps you bypass the PAM configuration file and easily modify global rules for user lockouts. Using Fail2Ban is a simple matter of installing it, enabling it, and then editing the configuration file to specific how many attempts a user can make before being locked out, and how long they should be locked out for. This helps prevent brute-force password cracking attempts.
Install Fail2Ban:
apt-get install fail2ban
Enable it:
systemctl start fail2ban && systemctl enable fail2ban
Edit the config file:
nano /etc/fail2ban/jail.local
Below is an excerpt of the jail.local config file where you can set the maximum number of login attempts before lockout:
# "bantime" is the number of seconds that a host is banned. bantime = 600 # A host is banned if it has generated "maxretry" during the last "findtime" # seconds. findtime = 600 maxretry = 3
Step 14: Check for hidden open ports with netstat
Open ports can reveal information about system or network architecture, and increase your attack surface. If you don’t need a port, close it. If you see an open port you don’t recognize, use netstat to investigate.
Use
netstat -antp
to check for hidden open ports.
Step 15: Scan for rootkits
A rootkit lurking on your server could be intercepting login details, concealing malware, providing a backdoor for an attacker, or even remotely controlling your server as part of a botnet. Rootkits are designed to be difficult to find, which is why you need a specialized tool for the job.
To do this, first install chkrootkit:
apt-get install chkrootkit
Next, simply type in chkrootkit as a root user. The tool will scan every part of your server and return details of anything suspicious.
Step 16: Install linux malware detect
Linux Malware Detect (LMD) is a malware scanner for Linux released under the GNU GPLv2 license, that is designed around the threats faced in shared hosted environments. It uses threat data from network edge intrusion detection systems to extract malware that is actively being used in attacks and generates signatures for detection. In addition, threat data is also derived from user submissions with the LMD checkout feature and from malware community resources. The signatures that LMD uses are MD5 file hashes and HEX pattern matches, they are also easily exported to any number of detection tools such as ClamAV.
cd /usr/local/src wget https://www.rfxn.com/downloads/maldetect-current.tar.gz tar xzfv maldetect-current.tar.gz
Source:
1. https://www.process.st/server-security/
2. https://www.rfxn.com/projects/linux-malware-detect/
3. https://www.howtoforge.com/tutorial/how-to-setup-automatic-security-updates-on-centos-7/