Subscribe to my newsletter for the latest updates. 👇

Kernel Hardening: Securing Your Linux Server

While the Linux kernel is fairly secure by default, there are steps we can take to make it even safer.

Kernel hardening can reduce the risk of certain network attacks and information leaks, making it harder for attackers to plan their attacks.

This guide will walk you through adjusting some kernel parameters to further enhance the security of your Linux server.

Preparation

To make the most of this guide, ensure you have a properly set up Ubuntu server.

If you don’t have one, consider getting a free VPS server to follow along.

Following along on your own server will enhance your understanding and practical experience.

Key Considerations

When you search the internet for guides on kernel hardening, you’ll come across various opinions.

I will not try to claim to have the correct information. Instead, I’ll share how I harden the Linux kernel on all my servers and my experience with it.

Leaving the default kernel parameters unchanged usually isn’t a problem and may not cause security issues. Tweaking some parameters just enhances your server’s security.

However, this might cause problems with what you run on your server if they rely on specific values.

That’s why I suggest testing these tweaks in a separate environment before applying them to your main server.

Lastly, I just want to mention that I’ve never encountered any problems with the tweaks I’ll be covering on all my Linux servers.

The /proc Directory

Before we dive into adjusting kernel parameters, let me first explain the /proc directory so you can understand where these parameters come from.

I prefer to provide context before delving into technical details.

If you look inside the /proc directory, you’ll find a bunch of numbered directories, and some regular files and directories.

The numbered directories correspond to process IDs (PIDs) of running processes.

Inside a numbered directory, you’ll find files and subdirectories filled with details about the running process.

However, not all files within these directories are easily understandable unless you’re familiar with OS programming.

Instead, we rely on commands like ps and top which extract process information from the /proc directory and present it in an easy-to-read format.

Now, let’s discuss the kernel.

The remaining files and directories with regular names contain details about the kernel’s activity.

The sys directory contains the kernel parameters that can be adjusted to harden the kernel.

If you enter the /proc/sys/net/ipv4/ directory, you’ll find various parameters related to IPv4 networking. Each file in this directory represents a parameter and holds its value.

Now that we know the basics of the /proc directory, it’s time to begin hardening the Linux kernel.

The sysctl Utility

The old method of changing parameter values involves echoing the new value to the parameter’s file.

This approach is outdated and doesn’t work with sudo, thus requiring the use of the bash -c command to enforce execution, as illustrated by the following example:

sudo bash -c "echo '1' > /proc/sys/net/ipv4/icmp_echo_ignore_all"

However, this isn’t the recommended approach.

Instead, we should use the sysctl utility, which offers a more modern solution.

The following command will list all parameters along with their values:

sudo sysctl -a

Additionally, you can also check a value for a certain parameter like this:

sudo sysctl net.ipv4.icmp_echo_ignore_all

You can use these two commands to verify if the new values have taken effect after you make changes.

If you want to change a parameter’s value temporarily, you could use the -w option to set the new value like this:

sudo sysctl -w net.ipv4.icmp_echo_ignore_all=1

It will last until you reboot the server.

Sometimes this is useful, but for the purpose of this guide, we want changes to be permanent.

We’ll tweak kernel parameters by adding them to the end of the /etc/sysctl.conf file along with their new values, ensuring that the changes become permanent.

Hardening The Linux Kernel

In the following three sections, I will show you the different parameters that I tweak.

Make sure to add them to the end of the sysctl.conf file.

After adding them, simply reboot the server for the new values to take effect.

We’ll start with these two parameters that help us prevent spoofing attacks:

net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1

A spoofing attack occurs when an attacker pretends to be someone else or a trustworthy entity.

This can occur at various levels, including the network level, such as IP address spoofing, where the attacker sends network packets with spoofed IP addresses.

Such tactics could be used for DoS attacks or to trick access controls.

These two parameters cause the server to verify if it can reach the source address in the packet header. If it can’t, the packets are rejected.

Next, add these parameters:

net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_syn_retries = 6
net.ipv4.tcp_synack_retries = 5

One form of DoS attack involves sending a huge number of SYN packets to a server without completing the three-way handshake, also known as SYN flood attacks.

This results in our server having numerous half-open connections, consuming significant resources and preventing it from accepting new legitimate connections.

These four parameters enable the use of TCP SYN cookies, which mitigate SYN flood attacks by efficiently managing half-open connections without consuming excessive server resources.

Next, add these parameters:

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
net.ipv4.conf.all.secure_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

These eight parameters will disable the sending or accepting of ICMP redirects, which could otherwise allow Man-in-the-Middle (MITM) attacks.

Next, add these parameters:

net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

Source routing enables the attacker to specify the route that packets should take through the network, potentially bypassing certain security measures. It can also cause Man-in-the-Middle attacks.

These four parameters will disable the acceptance of source routes packets.

Next, add these parameters:

net.ipv4.ip_forward = 0
net.ipv4.conf.all.forwarding = 0
net.ipv6.conf.all.forwarding = 0
net.ipv4.conf.default.forwarding = 0
net.ipv6.conf.default.forwarding = 0

Packet forwarding enables a system to transmit network packets from one network interface to another.

Unless your server is functioning as a router or VPN, packet forwarding should be disabled.

These parameters disable packet forwarding, thereby helping to prevent your server from being used as a gateway for unauthorized network traffic.

Next, add these parameters:

net.ipv4.tcp_sack = 0
net.ipv4.tcp_dsack = 0

These two parameters disable TCP Selective Acknowledgment (SACK), which is rarely used and commonly exploited.

Next, add this parameter:

net.ipv4.tcp_rfc1337 = 1

This parameter, when enabled, helps protect against TIME-WAIT Assassination or TCP TIME-WAIT attacks.

However, please note that the kernel documentation has confused some people about this parameter, and there is an ongoing debate about whether one should enable it or not.

Therefore, it’s advisable to test this parameter in a testing environment first.

Lastly, add this parameter:

net.core.bpf_jit_harden = 2

This parameter enables additional hardening features for the Berkeley Packet Filter (BPF) Just-In-Time (JIT) compiler.

Now, let’s proceed to adjust kernel-related parameters.

Add this parameter:

kernel.core_pattern = |/bin/false

Core dumps contain the recorded memory of a program when it crashes. They may contain sensitive information such as passwords and encryption keys.

This parameter helps restrict them.

Next, add this parameter:

kernel.unprivileged_bpf_disabled = 1 

This parameter prevents unauthorized users from loading and using BPF programs and restricts the BPF JIT compiler to root-only access.

This mitigates numerous potential attacks against the JIT compiler, such as heap spraying.

Next, add this parameter:

kernel.sysrq = 0

Magic Keys are specific key combinations that can be used to execute debugging and system control actions, even if the system is unresponsive due to a kernel panic or other issues.

This parameter disables Magic Keys, helping to secure the server by preventing potential misuse or exploitation of these debugging and control features.

Next, add this parameter:

kernel.dmesg_restrict = 1

By default, any user on the server could run the dmesg command, allowing them to view kernel information, some of which could be sensitive.

This parameter restricts the use of this command to users with root privileges.

Next, add this parameter:

kernel.yama.ptrace_scope = 3

The ptrace utility can be used to inspect and modify running processes.

Unless necessary, it should be disabled.

This parameter disables it.

Lastly, add this parameter:

kernel.unprivileged_userns_clone = 0

User namespaces are a kernel feature that enhances security by creating separate sandboxes for different users.

While available for unprivileged users, this feature could expose the kernel to privilege escalation.

This parameter restricts this feature to users with root privileges only.

Other Parameters

Processes that run with elevated privileges could still dump their memory even after adjusting the kernel.core_pattern parameter.

That’s why we need to disable core dumps using this parameter as well:

fs.suid_dumpable = 0

Similar to core dumps, swapping involves copying parts of the memory to the disk, potentially containing sensitive information.

That’s why we need to instruct the kernel to swap only when absolutely necessary using this parameter:

vm.swappiness = 1

Next, add these parameters:

fs.protected_regular = 2
fs.protected_fifos = 2

These two parameters prevent the creation of FIFOs (First In, First Out, also known as named pipes) and regular files in potentially insecure directories.

This enhances security by limiting attackers’ ability to create certain types of files in locations where they could potentially exploit them.

Lastly, add these parameters:

fs.protected_hardlinks = 1
fs.protected_symlinks = 1

The first parameter prevents users without read or write access to a file from creating hard links to it.

The second parameter controls how symbolic links (symlinks) are handled and ensures that symlinks can only be followed or used under certain conditions.

Together, these two parameters prevent certain security vulnerabilities known as TOCTOU (time of check and time of use) races.

Conclusion and Final Thoughts

Great job reaching the end!

In this guide, you’ve learned how to harden the Linux kernel to enhance the security of your server.

However, there’s more to securing Linux servers — advanced measures that I’ve covered comprehensively in my complete server security and hardening guide.

It’s a collection of all security and hardening measures with links to detailed guides for each.

By following these guides one by one, your server will be thoroughly secured.

If you found value in this guide or have any questions or feedback, please don’t hesitate to share your thoughts in the comments section below.

Your input is greatly appreciated, and you can also contact me directly if you prefer.

Newsletter

Subscribe to my newsletter for the latest updates 👇

2 Comments

    • Thank you for your kind comment! I’m glad you found the tutorial helpful.

      Yes, I do make some additional configurations to optimize Ubuntu for better performance. I’ll be putting together a tutorial on this soon to share the steps I take.

Leave a Reply

Your email address will not be published. Required fields are marked *