Abstract: We distinguish hardening a system from proper configuration and fortification. In this lecture, we describe areas of security tightening during the design and construction of systems rather than after their deployment.
We distinguish hardening a system from proper configuration and fortification. In this lecture, we describe areas of tightening security during the design and construction of systems rather than after their deployment. This distinction is not common yet. There exist several "hardening" scripts, e.g., Bastille, that just help do proper configuration.
There are "secure operating systems" and "trusted operating systems." Alas, no one can offer technically rigorous definitions for these terms. Windows NT, and several of Unix derivatives claimed, over the years, to be secure and trusted. For example, we found the following quote, early 2000s, "Windows NT is a secure operating system but only if it's configured correctly." Nevertheless, operating systems that lay claim to either being secure or trusted are better designed and engineered from their inception with a concern for security.
The space of hardening an OS is vast. It includes new ideas yet to be implemented in widely used OS (Windows, Linux, ...). It includes re-designing and re-implementing existing ideas such as "change-roots". It includes analyzing the source code of an OS extremely carefully by experts as well as via software tools based on mathematical proof techniques. The next few sections introduce these ideas further.
On Unix/Linux systems, the user called root or superuser, user id 0, can bypass all security restrictions. Windows systems have the "System" and "Administrator" accounts. The super user privilege should be split into many smaller privileges. E.g., a backup process should be able to read any file, but it should not be able to shut down the system, modify files, or send network packets. Processes, not users, should be given privileges. The backup program should be permitted to read all files, even though the administrator user who invokes the program should not be allowed such access. The backup process should not pass down its privileges to processes that it starts. The use of such finely divided abilities instead of sweeping powerful mechanisms is called the least privilege principle.
The traditional Unix model allows for access control of only files. So, a number of resources become "files": processes, hard disks, network interfaces, etc. In order to apply the principle of least privilege, we also need to divide the resources into finer units (often called objects, but unrelated to OOP). The users and processes are called subjects.
Capabilities is a word used with different meanings in the context of OS design. In OS research literature, processes hold tokens, called capabilities, denoting resources to be accessed and what can be done with them. Capabilities can be explicitly passed among processes. Linux, Windows, ... are not capability based in this sense. This usage of the word is unrelated to "POSIX capabilities" which are implemented in Linux and described later.
Newer OS designs add additional security attributes, called sensitivity labels (SLs), to files, processes, network interfaces, host addresses, and other resources based on how we wish to compartmentalize them. Access control using SLs is called mandatory access control (MAC). It is called mandatory because no inheritance of privileges is assumed. E.g., MAC can be applied at the network interface level. Incoming packets are assigned SLs, based on the source IP address or the network interface. Outgoing packets will have the label of the process that created them. A filtering rule can be formulated so that an incoming or outgoing packet can be dropped if the SL does not satisfy some conditions. MAC, in its academic form, is not about access control but about information flow.
There are Linux kernel modifications that accomplish the following. Secure policy enforcement; Supports read, write, append, execute, view, and read-only ptrace object permissions; Supports hide, protect, and override subject flags; Supports the PaX flags; Shared memory protection feature; Integrated local attack response on all alerts; Subject flag that ensures a process can never execute trojaned code; Intelligent learning mode that produces least-privilege ACLs with no configuration; Full-featured fine-grained auditing; Resource ACLs; Socket ACLs; File/process ACLs; Capabilities; Protection against exploit bruteforcing; /proc/pid filedescriptor/memory protection; ACLs can be placed on non-existent files/processes; ACL regeneration on subjects and objects; Administrative mode to use for regular sysadmin tasks; ACL system is resealed up admin logout; Globbing support on ACL objects; Configurable log suppression; Configurable process accounting; Human-readable configuration; Not filesystem dependent; Not architecture dependent; Scales well: supports as many ACLs as memory can handle; No runtime memory allocation; SMP safe; Include directive for specifying additional ACLs; Enable, disable, reload capabilities; Userspace option to test permissions on an ACL; Option to hide kernel processes;
We can divide the permissions/privileges based on the function ("role") they have, such as backup, file system integrity check, filtration of incoming packets. Each user is permitted a collection of roles. RBAC can implement MAC. There is a considerable amount of discrete mathematics developed for RBAC and MAC.
Attackers with root privileges can have access to any file. He can also access raw devices and corrupt the file system on it. We should mount important file volumes as read-only. But the ordinary mount cannot securely accomplish that because of access to raw devices. A read-only file system must disable file-write system calls and this would also prevent modifying file system through raw devices.
See the Buffer Overflow article.
Often, a privileged process first probes the state of a file and then takes subsequent action based on the results of that probe. If these two actions are not together atomic, an attacker can race between the actions (after the probe but before the resultant action), and exploit them. The attacker can exploit the race condition in different ways. The first way is during temporary file creation. The privileged program needs to create a temporary file, checks if any other file with the same name exists in the directory. If the file is not present it creates the file. An attacker exploits the race condition by creating a link file with the same name as the temporary file that points to a security sensitive file. The victim process, not aware of this, would open and write to the security sensitive file. The second variation of this exploit is done with a setuid program. The setuid process checks if the user has write access to a specific file before writing to the file. The attacker would race between the two actions: checking for access and writing to the file. Attacker would provide a file which has access to the user. After the setuid process checks for access and before it writes, the attacker replaces it with a link file of the same name pointing to a security sensitive file. The setuid process would then write into the file without any problem because it has already got privileges to write to that file. Let us suppose that there exists a setuid program that writes a user given string into a user given file. It takes two command line arguments: a message to be written and the file name. The program has to make sure that the user who started the process has write permissions to the file and also that the file is not a soft link.
No matter what design enhancements have been made, we should be prepared for intrusion, and hence must have OS functionality that can detect.
There is no proper logging in standard Linux kernel. In any system worthy of being protected, logging is necessary when system calls that require super user privileges are invoked, when a CPU general protection error occurs, when kernel denies a resource allocation to a process, and during module loading. Logging will help detect issues at least after the fact. On the other hand, there have been exploits that generated enormous amounts of logging causing a DoS.
The kernel data files in /proc directory give information about the running kernel. The address of various exported kernel symbols can be obtained from /proc/ksyms. An attacker having access to /dev/kmem can corrupt the kernel data structures with the help of symbol addresses in this file.
We must always assume that there can be (many unknown) ways of corrupting a kernel, running processes and loaded libraries. So kernel should include an integrity checking system which would check the integrity of kernel, while running, using crypto algorithms.
Source code review, both by human experts and automated software tools based on mathematical proof techniques, can reveal vulnerabilities. See the Secure Coding article.
We can enhance user account security through machine-generated passwords, biometric identification or access tokens. It is also important to not to trust other hosts until after host keys are verified. Linux Loadable Kernel Modules (LKM) do not have a proper authentication system before inserting the modules.
An operating system provides various facilities for processes that do a wide variety of jobs. A server machine is dedicated to serve a particular type of requests. In a server, all the facilities provided by the operating system are not required. Attackers can exploit these unnecessary features to compromise the system. Some of these features are required only during certain period of time such as during system initialization. Some of them are not required at any time. In Linux kernel, for example, loadable kernel module (LKM) support, is required only during system initialization. We recommend eliminating them at compile-time or freezing them dynamically or at least, restricting them for better security.
Stack smashing (buffer overflow) attacks are among the most common. By and large, these are programming errors that can be caught by analytical techniques. Newer compilers are mechanizing these techniques.
Many open source patches to Linux kernel prevent various attacks. Each patch has its own limitations and side effects. Patches released in binary form should in general be not trusted. Linux patches are source code. These replace section(s) of code in the kernel. Often a patch is in response to a newly discovered security hole. There are proactive modifications also in the open source OS. Open Wall Linux, e.g., is a collection of patches for non-executable stack, temporary file race condition prevention, restricted proc file system, special handling of file descriptors 0, 1, 2, destroy shared memory segments not in use, enforce RLIMIT_NPROC on execve, and privileged IP aliases.
Patches Aiming to Prevent Buffer Overflow: This includes Open Wall Linux patch, Segmented- PAX [Team 2003], KNOX [Purczynski 2003a], RSX module [Starzetz 2003], Paging-PAX, and Exec shield. All these source code patches aim to prevent stack and heap execution at kernel level by using either segmentation logic or paging logic or both.
Grsecurity [Spender 2003] is a suite of patches for the Linux kernel that attempt to improve the security of a Linux system. The use of principle of least privilege eliminates most of the security threats reported with standard operating systems. Trusted Path Execution (TPE) is one such mechanism. Traditionally, Trusted Path is one where the parent directory is owned by root and is neither group nor others writable. A file is said to be in the Trusted Path only if the directory of the file is owned by root and it has neither group nor others writable permissions. TPE works based on an internal list of trusted user ids. If a given user tries to execute a file not in the Trusted Path, and their user id is not in the kernels trusted list, they are denied execution privileges. This is known as Trusted Path Execution. TPE is highly recommended for server environments. TPE is not a feature of standard Linux kernel. Some of the features of Grsecurity are Trusted Path Execution, Process-based Mandatory Access Control, Access control lists, chroot restrictions, randomizing PIDs, IP IDs, TCP initial sequence numbers, trusted path implementation, and FIFO restrictions.
REference Monitor for UNIX Systems [Bernaschi et al. 2002] is a kernel patch which intercepts system calls without requiring changes to syntax and semantics of existing system calls. REMUS presents a complete classification of the system calls according to the level of threat. The main focus is on the system calls which can be exploited by the attackers to get complete control of system or become a superuser. REMUS isolates a subset of system calls and tasks critical to system security and hence allow reduction of monitoring overhead.
RSBAC [Ott 2001], Rule Set Based Access Control, is designed according to the Generalized Framework for Access Control (GFAC) to overcome the deficiencies in access control in standard Linux systems, and to make a flexible combination of security models as well as proper access logging possible. The abstraction makes the framework and the existing model implementations easily portable to other operating systems. Among the implemented models are Mandatory Access Control, Linux Capabilities, Access Control Lists, Role Compatibility, Privacy Model, and Functional Control.
The Linux Security Module (LSM) [Wright et al. 2002] project has developed a light-weight, general purpose, access control framework for the main stream Linux kernel that enables many different access control models to be implemented as loadable kernel modules. Several existing access control implementations including Linux capabilities, Security Enhanced Linux, Domain, and Type enforcement have already been adapted to use LSM framework. This LSM framework is available as a patch to kernel source. LIDS LIDS [XIE and Biondi 2003], Linux Intrusion Detection System, is a kernel patch whose main focus is on Access Control Lists. The features include enhancements to Linux capabilities, protecting important files, protecting Raw I/O devices, protecting important processes, and port scan detector at the kernel level.
LIDS (Linux Intrusion Detection System) is a series of kernel patches that enable loadable module and mount point locking.
RaceGuard [Cowan et al. 2001] is a secure kernel modification which aims to prevent the temporary file creation race condition exploits. It detects the pertinent changes in the file system between the time an application probes for a nominated temporary file name and the time the file is created. In a RaceGuard kernel, each process keeps a cache of potential temporary file races. This cache is just a list of file names associated with the process descriptor. If the process probes for a file and it is non-existent, the process cache is updated with the name of the file. If file creation hits a file that already exists, and the name matches a name in RaceGuard cache, then it is regarded as a race attack and so the open system call aborts. If the file creation succeeds without conflicts, then it is cleared from the cache. Note that RaceGuard cannot defend against the file swap type of attacks.
Instead of fighting the race conditions, Openwall restricts the links in the world writable directories such as /tmp to prevent these attacks. Since attacks are typically done in the world writable directories and an attacker would typically create a soft link or hard link to security sensitive file, Openwall patch imposes restrictions on hard and soft links. Soft Link In a directory with +t (sticky bit set), the process cannot follow a soft link unless the link is owned by the user or the owner of the link is the owner of the directory. Hard Link A process can create a hard link to a file only when the file is owned by the user or the user has permissions to read and write the file. Though Openwall patch cannot prevent all types of file creation race condition attacks, it certainly makes some of them impossible and others more difficult to succeed. Since in both temporary file creation and file swap attacks link files are used, Openwall patch can prevent them. However, because of this patch, some applications that require soft links in /tmp directory may break. We prefer the Openwall patch to Raceguard.
Security-Enhanced Linux (SELinux) is a contribution by National Security Agency. It restricts the actions that programs can take. AppArmor identifies file system objects by path name instead of inode. This means that, for example, a file that is inaccessible may become accessible under AppArmor when a hard link is created to it, while SELinux would deny access through the newly created hard link. On the other hand, data that is inaccessible in SELinux may become accessible when applications update the file by replacing it with a new version a frequently used technique while AppArmor would continue to deny access to the data. In both cases, a default policy of "no access" avoids the problem.
PaX patches provide address space modification protection: Segmentation-based implementation of non-executable pages; Mprotect restrictions prevent new code from entering a task; Randomization of stack and mmap base; Randomization of heap base; Randomization of executable base; Randomization of kernel stack; Automatically emulate sigreturn trampolines; No ELF .text relocations; No kernel modification via /dev/mem, /dev/kmem, or /dev/port; Option to disable use of raw I/O; Removal of addresses from /proc/<pid>/ [maps|stat].
Every process has a current working directory that it begins with and a root directory, which is used to resolve the absolute path names of files. By default, the root directory of a process is /. Chroot system call changes the directory that is considered the root of a process. All subsequent absolute path names of a file are resolved with respect to the new root. The process cannot access files that are outside of the tree rooted at the new root directory, even in the presence of hard or symbolic links. Such a process is said to be in a chroot jail. Server daemons, such as anonymous FTP server, and web server, where the processes need only access to a limited sub tree, are run inside a chroot jail for security reasons. Unfortunately, weaknesses exist, and a jailed super user process can break out of it. Linux chroot restricts only the real (e.g., persistent storage media) file system access of the processes in the jail. Using interprocess communication mechanisms such as domain sockets, shared memory segments, and signals, a jailed process can damage the rest of the system.
By exploiting chroot, chdir, fchdir system calls, an attacker with root privileges can break chroot jail. None of the three system calls check to make sure that current working directory (cwd) is within the root directory of the process. When a process calls chroot, the root directory of the process is changed but cwd is left unchanged. If process has a directory open, which is outside the root directory, it can call fchdir to that directory and the cwd of the process changes to that directory. Once the cwd goes out of the root directory of the process, the process is successful in breaking the chroot jail.
You may wish to do this experiment on your own home PC.
linux to it.