TL;DRIn this article, we explore hardening schemes that work out of the box in five popular Linux distributions. For each, we took the default kernel configuration, loaded all packages, and analyzed the protection schemes in nested binaries. The distributions considered are OpenSUSE 12.4, Debian 9, CentOS, RHEL 6.10 and 7, as well as Ubuntu 14.04, 12.04, and 18.04 LTS.
The results confirm that even basic schemes, such as stack canaries and position-independent code, are still not widely used. The situation is even worse for compilers when it comes to protection against vulnerabilities like stack clash, which gained attention in January after the disclosure of However, not everything is hopeless. A significant portion of binaries implement basic protection methods, and their number is increasing with each version.
The assessment showed that the highest number of protection methods is implemented in Ubuntu 18.04 at the OS and application levels, followed by Debian 9. On the other hand, OpenSUSE 12.4, CentOS 7, and RHEL 7 also implement basic protection schemes, with stack clash protection being applied even more broadly with a much denser default package set.
Introduction
Ensuring high software quality is challenging. Despite the vast array of advanced tools for static code analysis and dynamic runtime analysis, as well as significant progress in compiler and programming language development, modern software still suffers from vulnerabilities that are constantly exploited by malicious actors. The situation is exacerbated in ecosystems that include legacy code. In such cases, we not only face the perennial challenge of identifying potential exploitable bugs but are also constrained by rigid backward compatibility requirements that often necessitate retaining outdated, and in worse cases, vulnerable or buggy code.
This is where protection or hardening methods come into play. Some types of errors we are unable to prevent, but we can make life harder for attackers and partially address the problem by preventing or obstructing exploitation these errors. Such protection is used in all modern operating systems, but the methods vary significantly in complexity, effectiveness, and performance: from stack canaries and to full-fledged protections and . In this article, we will examine what protection methods are employed in the most popular Linux distributions by default, as well as explore the properties of binaries distributed through the package management systems of each distribution.
CVE and security
We have all seen articles with titles like "The Most Vulnerable Applications of the Year" or "The Most Vulnerable Operating Systems." Typically, they present statistics on the total number of records for vulnerabilities of the type , obtained from from and other sources. Consequently, these applications or OS are ranked based on the number of CVEs. Unfortunately, while CVEs are very useful for tracking issues and informing vendors and users, they say little about the actual security of the software.
For example, let’s look at the total number of CVEs over the past four years for the Linux kernel and the five most popular server distributions, namely Ubuntu, Debian, Red Hat Enterprise Linux, and OpenSUSE.

Figure 1
What does this graph tell us? Does a higher number of CVEs mean that one distribution is more vulnerable than another? The answer is no. For instance, in this article, you will see that Debian implements stricter security mechanisms compared to OpenSUSE or Red Hat Linux, yet Debian has more CVEs. However, this does not necessarily mean weakened security: the presence of CVEs does not indicate whether a vulnerability is exploitable. Severity scores provide insight into how likely it is that a vulnerability will be exploited, but ultimately exploitability largely depends on the defenses present in the affected systems, as well as the resources and capabilities of malicious actors. Moreover, the absence of CVE reports does not indicate anything about other unregistered or unknown vulnerabilities. незарегистрированных или неизвестных vulnerabilities. The difference in CVE may be explained not by the quality of the software but by other factors, including the resources allocated for testing or the size of the user base. In our example, a higher number of CVE for Debian may simply indicate that Debian provides more software packages.
Of course, the CVE system provides useful information that allows for creating appropriate defenses. The better we understand the reasons for program failures, the easier it is to identify potential exploitation methods and develop corresponding mechanisms. detection and response. Figure 2 shows categories of vulnerabilities for all distributions over the past four years (). It is immediately clear that most CVEs fall into the following categories: denial of service (DoS), code execution, overflow, memory corruption, information leakage (exfiltration), and privilege escalation. Although many CVEs are counted multiple times in different categories, the same issues persist year after year. In the next part of the article, we will evaluate the use of various protection schemes to prevent the exploitation of the specified vulnerabilities.

Figure 2
Since I have already learned to "somewhat" port QEMU to JavaScript, this time it was decided to do it wisely and not repeat past mistakes.
In this article, we intend to answer the following questions:
- What is the security of various Linux distributions? What protective mechanisms exist in the kernel and user space applications?
- How has the adoption of protection mechanisms changed over time for different distributions?
- What are the average dependencies of packages and libraries for each distribution?
- What protections are implemented for each binary?
Choice of distributions
It turns out to be difficult to find accurate statistics on distribution installations, as in most cases the number of downloads does not indicate the number of actual installations. Nevertheless, Unix options make up the majority of server systems (69.2% on web servers, according to W3techs and other sources), and their share is continually growing. Thus, for our research, we focused on distributions available out of the box on the platform . In particular, we selected the following OS: Distribution/version
Build
Kernel
OpenSUSE 12.4
4.12.14-95.3-default
Debian 9 (stretch)
#1 SMP Wed Dec 5 06:00:48 UTC 2018 (63a8d29)
4.9.0-8-amd64
CentOS 6.10
#1 SMP Debian 4.9.130-2 (2018-10-27)
2.6.32-754.10.1.el6.x86_64
3.10.0-957.5.1.el7.x86_64
#1 SMP Tue Jan 15 17:07:28 UTC 2019
CentOS 7
Red Hat Enterprise Linux Server 6.10 (Santiago)
#1 SMP Fri Feb 1 14:54:57 UTC 2019
2.6.32-754.9.1.el6.x86_64
Red Hat Enterprise Linux Server 7.6 (Maipo)
#1 SMP Wed Nov 21 15:08:21 EST 2018
3.10.0-957.1.3.el7.x86_64
3.10.0-957.1.3.el7.x86_64
#1 SMP Thu Nov 15 17:36:42 UTC 2018
Ubuntu 14.04 (Trusty Tahr)
4.4.0–140-generic
#166~14.04.1-Ubuntu SMP Sat Nov 17 01:52:43 UTC 20…
Ubuntu 16.04 (Xenial Xerus)
4.15.0–1026-gcp
#27~16.04.1-Ubuntu SMP Fri Dec 7 09:59:47 UTC 2018
Ubuntu 18.04 (Bionic Beaver)
4.15.0–1026-gcp
#27-Ubuntu SMP Thu Dec 6 18:27:01 UTC 2018
Table 1
Analysis
We will examine the default kernel configuration and the properties of the packages available through the package manager for each distribution out of the box. Thus, we consider only packages from the default mirrors of each distribution, ignoring packages from unstable repositories (for example, the 'testing' mirrors in Debian) and third-party packages (like Nvidia packages from standard mirrors). Additionally, we do not consider user-compiled kernels or configurations with enhanced security.
Kernel Configuration Analysis
We applied an analysis script based on . We examine the out-of-the-box security parameters for the mentioned distributions and compare them with the list from (KSPP). For each configuration parameter, Table 2 describes the desired setting: a checkmark indicates distributions that comply with KSSP recommendations (for clarification of terms see ; in future articles, we will discuss how many of these protective measures were developed and how to compromise the system in their absence).

Overall, newer kernels have stricter out-of-the-box settings. For instance, CentOS 6.10 and RHEL 6.10 on kernel 2.6.32 lack most critical features implemented in newer kernels, such as , strict RWX permissions, address randomization, or copy2usr protection. It should be noted that many of the configuration options from the table are absent in older kernel versions and are not applicable in practice — in the table, this is nevertheless indicated as lack of adequate protection. Similarly, if a configuration parameter is absent in this version, and disabling this parameter is necessary for security, this is considered a reasonable configuration.
Another point when interpreting results: some kernel configurations that increase the attack surface can also be used for security. Examples include uprobes and kprobes, kernel modules, and BPF/eBPF. Our recommendation is to utilize the aforementioned mechanisms for providing real protection, as they are non-trivial to use, and their exploitation assumes that malicious actors are already embedded in the system. However, if these options are enabled, the system administrator must actively monitor for abuses.
Examining the entries in Table 2 further, we see that modern kernels provide several options for protecting against the exploitation of vulnerabilities such as information leaks and stack/heap overflows. However, we note that even the latest popular distributions have not yet implemented more complex protections (for example, with patches ) or modern protections against code reuse attacks (such as ). What's worse, even these more advanced protections do not safeguard against the full spectrum of attacks. Thus, it is crucial for system administrators to complement reasonable configurations with solutions that offer detection and prevention of exploits at runtime.
Application Analysis
It is not surprising that different distributions have varying package characteristics, compilation options, library dependencies, etc. Differences exist even for distributions and packages with a minimal number of dependencies (for example, coreutils in Ubuntu or Debian). To evaluate the differences, we downloaded all available packages, extracted their contents, and analyzed the binaries and dependencies. For each package, we tracked other packages on which it depends, and for each binary, we tracked its dependencies. In this section, we will summarize the findings.
Distributions
In total, we have uploaded 361,556 packages for all distributions, extracting only packages from default mirrors. We ignored packages without ELF executable files, such as source codes, fonts, etc. After filtering, 129,569 packages remained, containing a total of 584,457 binary files. The distribution of packages and files across distributions is shown in Fig. 3.

Fig. 3
It can be observed that the more modern the distribution, the more packages and binary files it contains, which is logical. Furthermore, the packages for Ubuntu and Debian include significantly more binary files (both executables and dynamic modules and libraries) than CentOS, SUSE, and RHEL, which potentially affects the attack surface of Ubuntu and Debian (it should be noted that the figures reflect all binaries from all package versions, meaning some files are analyzed multiple times). This is particularly important given the dependencies between packages. Thus, a vulnerability in a binary of one package can impact many parts of the ecosystem, just as a vulnerable library can affect all binary files that import it. As a starting point, let’s examine the distribution of dependency counts across packages in various OSs:
Fig. 4
In almost all distributions, 60% of packages have at least 10 dependencies. Moreover, some packages have significantly more dependencies (over 100). The same applies to reverse package dependencies: as expected, several packages are used by many other packages in the distribution, so vulnerabilities in these select few carry a high risk. As an example, the following table lists 20 packages with the maximum number of reverse dependencies in SLES, CentOS 7, Debian 9, and Ubuntu 18.04 (each cell indicates the package and the number of reverse dependencies).

Table 3
An interesting fact. Although all analyzed OSs are built for the x86_64 architecture, and most packages are defined for the x86_64 and x86 architectures, packages often contain binary files for other architectures, as shown in Fig. 5.

Fig. 5
In the next section, we will delve into the characteristics of the analyzed binaries.
Statistics on binary file protection
As an absolute minimum, it is necessary to study the basic set of protection options for existing binary files. Several Linux distributions come with scripts that perform such checks. For example, in Debian/Ubuntu, there is such a script. Here is an example of its operation:
$ hardening-check $(which docker)
/usr/bin/docker:
Position Independent Executable: yes
Stack protected: yes
Fortify Source functions: no, only unprotected functions found!
Read-only relocations: yes
Immediate binding: yesThe script checks five :
- Position Independent Executable (PIE): indicates whether the text section of a program can be relocated in memory to achieve randomization if ASLR is enabled in the kernel.
- Stack Protected: indicates whether stack canaries are enabled to protect against stack collision attacks.
- Fortify Source: indicates whether unsafe functions (e.g., strcpy) are replaced with their safer counterparts, while runtime checks are replaced with their unchecked equivalents (e.g., memcpy instead of __memcpy_chk).
- Read-only relocations (RELRO): indicates whether relocation table entries are marked as "read-only" if they were triggered before program execution begins.
- Immediate binding: indicates whether the runtime linker resolves all relocations before the program begins execution (this is equivalent to full RELRO).
Are the aforementioned mechanisms sufficient? Unfortunately, no. There are known methods to bypass all of the above protections, but the more stringent the protection, the higher the bar for the attacker. For example, are harder to apply if PIE and immediate binding are in effect. Similarly, full ASLR requires additional work to create a working exploit. However, sophisticated attackers are already prepared to confront such protections: their absence essentially accelerates a breach. Therefore, it is crucial that these measures are viewed as essential. at least.
We wanted to study how many binary files in the examined distributions are protected by these, as well as three other methods:
- The non-executable bit () prevents execution in any region that should not be executable, such as the stack heap, etc.
- indicates the runtime path used by the dynamic loader to search for the appropriate libraries. The former is mandatory. For any modern system: its absence allows attackers to arbitrarily write a payload into memory and execute it as is. For the second, incorrect execution path configurations allow for the introduction of unreliable code, potentially leading to a number of issues (for example, , as well as ).
- Stack collision protection safeguards against attacks that force the stack to overlap with other memory areas (for instance, the heap). Given the recent exploits that abuse , we deemed it appropriate to include this mechanism in our dataset.
So, without further ado, let's move to the numbers. Tables 4 and 5 contain a summary of the analysis of executable files and libraries from various distributions, respectively.
- As can be seen, NX protection is implemented everywhere, with rare exceptions. Notably, there is somewhat lower usage in the Ubuntu and Debian distributions compared to CentOS, RHEL, and OpenSUSE.
- Stack canaries are often absent, especially in distributions with older kernels. Some progress is observed in the latest distributions of CentOS, RHEL, Debian, and Ubuntu.
- With the exception of Debian and Ubuntu 18.04, the support for PIE is poor in most distributions.
- Stack collision protection is weakly implemented in OpenSUSE, CentOS 7, and RHEL 7 and is practically absent in the others.
- All distributions with modern kernels have some support for RELRO, with Ubuntu 18.04 leading, followed by Debian.
As previously mentioned, the metrics in this table are averages across all versions of the binary file. If only the latest versions of the files are considered, the numbers will differ (for example, see ). Moreover, most distributions usually check the protections of only a few functions in the binary code when counting statistics, while our analysis provides the true percentage of fortified functions. Therefore, if 5 out of 50 functions are protected in a binary, we will assign it a score of 0.1, which corresponds to 10% fortified functions.

Table 4. Protection characteristics for executable files shown in Figure 3 (implementation of corresponding functions as a percentage of the total number of executable files)

Table 5. Protection characteristics for libraries shown in Fig. 3 (implementation of corresponding functions as a percentage of the total number of libraries)
So, is there progress? Definitely: this is evident from the statistics of individual distributions (for example, ), as well as from the tables provided above. For instance, Fig. 6 shows the implementation of protective mechanisms in three successive Ubuntu LTS distributions (we have omitted the stack collision protection statistics). We observe that from version to version, more and more files support stack canaries, and increasingly, more binary files are supplied with full RELRO protection.
Fig. 6
Unfortunately, a number of executables in different distributions still lack any of the aforementioned protections. For example, looking at Ubuntu 18.04, we can notice the binary ngetty (a replacement for getty), as well as the shells mksh and lksh, the picolisp interpreter, the nvidia-cuda-toolkit packages (a popular package for GPU-accelerated applications such as machine learning frameworks), and klibc-utils. Similarly, the binary mandos-client (an administrative tool that allows automatic reboots of machines with encrypted file systems), as well as the rsh-redone-client (a reimplementation of rsh and rlogin), are delivered without NX protection, even though they have SUID rights :(. Additionally, several suid binaries lack basic protection, such as stack canaries (for example, the Xorg.wrap binary from the Xorg package).
Summary and concluding remarks
In this article, we highlight several security features of modern Linux distributions. Analysis shows that the latest Ubuntu LTS distribution (18.04) implements, on average, the strongest OS and application level protection among distributions with relatively new kernels, such as Ubuntu 14.04, 12.04, and Debian 9. However, the examined CentOS, RHEL, and OpenSUSE distributions in our dataset by default provide a denser package set, and in the latest versions (CentOS and RHEL), have a higher percentage of stack collision protection implementations compared to Debian-based competitors (Debian and Ubuntu). When comparing versions of CentOS and RedHat, we notice significant improvements in the implementation of stack canaries and RELRO from versions 6 to 7, but on average, CentOS implements more features than RHEL. Overall, all distributions should pay special attention to PIE protection, which, with the exception of Debian 9 and Ubuntu 18.04, is implemented in less than 10% of the binary files in our dataset.
Finally, it should be noted: while we conducted the research manually, there are many security tools (for example, , , ), which perform analysis and help avoid unsafe configurations. Unfortunately, even strong protection in reasonable configurations does not guarantee the absence of exploits. This is why we firmly believe that it is vital to ensure , focusing on exploitation patterns and preventing them.
Source: habr.com
