File permissions offer a safe alternative to SUID executables, but they may seem a bit confusing at first.
I will save you time if you want to avoid a detailed reading of the article above: in essence, file permissions allow processes that run as root and, therefore, have the right to do something, retain certain limited features this listwhen they reset privileges and are started by an unprivileged user. This means that if an attacker manages to compromise a process by overflowing a buffer or other exploit, he will not be able to take advantage of anything other than certain minimum privileges that the process really needs.
Permissions are great for services that usually always run as root, but what about command line utilities? Fortunately, this is also supported provided that you have the correct utilities installed. If you use Ubuntu, for example, you will need a package
libcap2-bin. You will also need to run a non-archaic kernel (starting with version 2.6.24)
These functions allow you to associate permissions with executable files in the same way as setting the SUID bit, but only for a specific set of permissions. Utility
setcap used to add and remove permissions from a file.
The first step is to select the permissions you need. For this article, I assume that there is a network diagnostic tool called
tracewalkwhich should be able to use raw sockets. This usually requires the application to run as the root user, but when viewing the list it turns out that only permission is required
Assuming you are in the directory where the binary is located
tracewalk, you can add this permission as follows:
sudo setcap cap_net_raw=eip tracewalk
Ignore suffix for now
=eip for permission, I will talk about this in a couple of seconds. Note that the permission name is lowercase. Now you can check if you have configured permissions correctly with:
setcap -v cap_new_raw=eip tracewalk
Or you can list all permissions set for this executable file:
For reference, you can also remove all permissions from the executable using:
setcap -r tracewalk
At this point, you should be able to run the executable as an unprivileged user, and he should be able to work with raw sockets, but not have any other privileges that the root user has.
So what does this weird suffix mean
=eip? This will require a bit of understanding of the nature of permissions. Each process has three sets of permissions – effective, inheritable and permitted (effective, inheritable and permitted):
- Effective Permissions are those that determine what a process can actually do. For example, it cannot deal with raw sockets if
CAP_NET_RAWnot in an effective set.
- Available (Permitted) permissions are those that a process is allowed to have if it requests them using the appropriate call. They do not allow a process to actually do anything unless it was specifically written to request the specified permission. This allows you to write processes to add critical permissions to the effective set only for the period when they are really needed.
- Inheritable permissions are those that can be inherited in the available set of child child processes. During surgery
clone()the child process is always given a copy of the permissions of the parent process, because at this point it is still executing the same executable file. Inherited set is used when
exec()(or equivalent) is called to replace the executable with another. At this point, the available process set is masked by the inherited set to obtain the available set that will be used for the new process.
setcap allows us to add permissions of these three sets independently for a given executable file. Note that the meaning of groups is interpreted a little differently for file permissions:
- Available file permissions are those that are always available for the executable file, even if the parent process that called it did not have them. They used to be called “forced” permissions.
- Inherited file permissions define an additional mask that can also be used to remove permissions from the set of the calling process. They are used in addition to the inherited set of the calling process, so permission is inherited only if it exists in both sets.
- Effective file permissions are actually just one bit, not a set, and if it is installed, it means that the entire available set is also copied into the effective set of the new process. This can be used to add permissions to processes that were not specifically written to request them. Since this is one bit, if you set it for any permission, it must be set for all permissions. You can think of it as a legacy bit because it is used to allow the use of permissions for applications that do not support them.
When specifying permissions through
setcap three letters
p refer to efficient, inherited and affordable sets, respectively. So, the earlier specification:
sudo setcap cap_net_raw=eip tracewalk
… indicates that resolution
CAP_NET_RAW must be added to accessible and inherited sets and that the effective bit must also be set. This will replace any previously set permissions in the file. To set multiple permissions at once, use a comma separated list:
sudo setcap cap_net_admin,cap_net_raw=eip tracewalk
Permissions Guide discusses all this in more detail, but I hope this post demystified the incident a little. It remains to mention only a few warnings and tricks.
First, file capabilities do not work with symlinks – you must apply them to the binary itself (that is, to the target of the symlink).
Secondly, they do not work with interpreted scripts. For example, if you have a Python script that you want to assign permission to, you must assign it to the Python interpreter itself. Obviously, this is a potential security problem, because then all scripts executed with this interpreter will have the specified permission, although this is still much better than doing the SUID. The most common workaround, apparently, is to write a separate executable file in C or an analogue that can perform the necessary operations and call it from a script. This is similar to the approach used by Wireshark, which uses a binary
/usr/bin/dumpcap to perform privileged operations:
$ getcap /usr/bin/dumpcap /usr/bin/dumpcap = cap_net_admin,cap_net_raw+eip
Third, file permissions are disabled if you use an environment variable
LD_LIBRARY_PATH for obvious security reasons(1). The same goes for
LD_PRELOAD, as far as I know.
1. Since an attacker can obviously replace one of the standard libraries and use
LD_LIBRARY_PATHto force its library to be called in preference over the system one, and therefore have its own arbitrary code executed with the same privileges as the calling application.
That’s all. Details of the course program can be found on webinar to be held on January 24th.