Access Control

One of the biggest challenges in computer security is preventing one program from interfering with another. For instance, you do not want a virus to be able to steal the passwords from your browser. For this reason, operating systems implement protection mechanisms that enable the isolation of multiple processes and restrict access to data.

In Linux, the kernel is the program that has unrestricted access to the whole machine. All other programs run as a specific identity and have their access mediated by the kernel. Access decisions are made on the basis of the userid/groupid associated with the program. If the user is root (userid = 0), access is always granted by the kernel. Users usually have a default group, but they may belong to several additional groups. By joining an existing group, a user inherits the permissions it grants.

Unix permissions

Using the ls -l command we can display the Unix permissions set to a file or a directory:

Each file has a owner and a group, in this case it is user r1x and group r1x. The first column rw-rw-r-- is made of 3 triads defining the permissions granted to the owner, to the group and to all the other users, respectively. Each permission triad is commonly made up of the following characters:

  • r: the file can be read / the directory’s contents can be shown
  • w: the file file can be modified / the directory’s contents can be modified
  • x: the file can be executed / the directory can be traversed
  • s: the file is setuid if s is found in the user triad (setgid if s is in the group triad). Implies x. Enables the file to run with the privileges of its owner

Notice that modern Linux distributions, upon user creation, usually add a group to the system with the same name of the user being added and set this group as the primary user’s group.

As mentioned before, the set of permissions of an user includes the permissions assigned to his groups. In the following example file rootfile is owned by root and has group users. It gives read and write permissions to root and only read permission to users:

Unix permissions can be altered using the chmod command (using the symbolic mode or the numeric one), whilst the owner and group can be set using chown. Notice that non-root users can change the group (to one they belong to) but not the ownership.

Access Control Lists (ACL)

Suppose we are in a shared hosting system where users are allowed to host personal websites in their home directories. The webroot of the user r1x is the world-readable directory /home/r1x/webroot. The home directory of r1x can be accessed only by the user itself:

In order to allow the webserver process (running as nginx:nginx) to access the webroot directory, we could make even the /home/r1x world-traversable using chmod o+x. Sadly, by doing so we would enable everyone (not just the webserver) to read files in the user home directory just by knowing the path name, including the sensitive file personal_notes.txt!

Access Control Lists provide an additional, more fine grained permission mechanism for files and directories. With ACLs it is possible to define different permissions on a per-user/per-group basis. They have higher priority over Unix permissions and provide inheritance of attributes from directories to files. Going back to the webserver example, we can make good use of the ACLs by granting the x permission on /home/r1x/ only to the nginx user!

The command setfacl is used to define ACLs, while getfacl allows to display them. To provide an example, we first create a test file in the current directory and print its ACL

Now we change the ACL so that the user r1x can read and write the newly created file

The mask entry reported by the getfacl output is called the effective rights mask. This entry limits the effective rights that can be granted to the user and group ACL. By tightening the mask further, we revoke the write permission previously granted to the user r1x

To remove an ACL from a file one can use the -b option

See man getfacl and man setfacl for further details. Also notice how the output of ls -l is affected by the presence of an ACL: in addition to the + symbol, the file permission bits reported by ls may not correspond to the actual Unix permissions. To understand the correspondance between ACL entries and file permission bits read the relevant section in the manual page of acl by typing man 5 acl.

Downsides of the traditional access control mechanism

There are various problems with the traditional Unix access control system.

  • First of all, the root user. An attacker gaining root privileges is all-powerful and might even alter the system logs to hide his malicious activities or to implant fake audit trails. It is possible, however, to limit the need of setuid root binaries by giving to specific processes a subset of superuser permissions via Linux capabilities (see below).
  • Second, an application running on behalf of a user has access to all the resources owned by that user. Think about a browser, which is an application perpetually running potentially-malicious code, and a sensitive resource like a private ssh RSA key: if the browser has a vulnerability, the attacker might get access to the private key, since the browser is running with the same permissions as the user.

    To mitigate this problem, some browsers implement layered sandboxes to prevent unauthorised access to system resources. Check the Linux sandboxing approach implemented by Google Chromium for further details.

  • Third is the lack of a centralised access control policy. Permissions are attached to resources making impossible for a system administrator to fully understand the security implications of all the single permissions leaving space for backdoors.
  • Last, users can take their own access decisions about their resources. Even if this might appear irrelevant for a single-user Desktop computer, it is a problem of crucial importance when the user is a member of an organisation and is entrusted with sensitive files. For this reason, the standard Unix access control system is called Discretionary, as opposed to Mandatory Access Control systems where a security policy is enforced independently of user actions. Example of Mandatory Access Control systems are SELinux, AppArmor and grsecurity for Linux and MIC in Windows.

Linux Capabilities

Linux Capabilities offer the possibility of giving to specific processes a subset of superuser permissions. This can be also achieved via setuid root (s) permission, but executing the whole program as root is more risky in case of vulnerabilities.

Example 1: ping

We consider the case study of the ping program:

In the terminal (not here because of the different colouring done by wordpress), we notice that /bin/ping appears in a different color even if permissions look standard (in particular we do not see any s). This is a way for ls to make it visible that capabilities have been set for this binary. With getcap we can check what capabilities are set and we discover cap_net_raw+ep, meaning that cap_net_raw is permitted (p) and effective (e). cap_net_raw allows for raw access to network which is necessary for ICMP packets in ping. Giving this capability to ping is safer than giving setuid root permission, which would give full root access to the program.

Example 2: tcpdump

tcpdump permits to dump any packet sent and received by the host. Similarly to ping it would require cap_net_raw capability, but is not provided by default. Thus, non-root users cannot run tcpdump unless permissions are suitably changed.

We first show that by setting setuid root permission tcpdump becomes executable by non-root users:

Now if we run tcpdump as non-root user the program starts correctly, since it is run with root privileges:

A better solution is to give tcpdump cap_net_raw capability as done by default for ping:

tcpdump can still be run as non-root but now it only retains the cap_net_raw privileged capability, while running as the non-root user.

Capabilities should not be abused

It is important to keep in mind that giving capabilities weakens security and gives non-root users access to privileged operations. We use again tcpdump as a case study and we show how to simply eavesdrop a network communication.

netcat: the tcp/ip swiss army knife

We use netcat (nc) to setup a simple network connection. Execute the following on one host where you can run tcpdump:

This starts netcat in server mode and listens on port 10000. You can connect to this netcat instance from a different host with:

This basically start a ‘commandline chat’ between the two hosts. netcat, in fact, is like ‘cat’ on the network: it redirects input/output from/to terminal and network.

Using tcpdump to intercept traffic

We illustrate simple interception. To simplify we work directly on the host where the server nc is running. In practice, to intercept it is necessary to have access to the client-server connection. Either we are in the middle (e.g. on a router host) or we are on the same LAN and we perform some spoofing attack to force client-server packets to go through our host. We “simulate” this by directly acting on the server host.

The program tcpdump is a simple but powerful tool that allows you to easily sniff. We report a few usage examples from the man page:

The following asciicast show how to use tcpdump to sniff the netcat chat:

We report below some useful options:

tcpdump shows the raw packets including headers. If you want to display just the payload you can use the tcpflow tool. For example, here we sniff a netcat chat:

Option -c prints on the console. Without this option output is saved on file whose name are the IPs and ports as above.

Privilege drop

It is worth noticing that many administrative programs automatically drop root privileges whenever they do not need privileged capabilities in the subsequent execution. We can observe this running tcpdump as root and observing the syscalls through strace (we grep on uid to filter out the interesting calls):

We see that, after a while, tcpdump sets the user id to 101 which is user tcpdump. This confirms that, after tcpdump has accessed the network with raw capabilities, it drops privileges and go on with non-root user permissions. This is an important strategy to reduce the attack surface to the portion of code that really requires privileged access.


Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.