Lab03 - Part02 - Capability Lists Implementation in Linux
Lab03 - Part02 - Capability Lists Implementation in Linux
CENG685 –
Information
Security
Lab 04 – Capability Lists
Implementation in Linux
1. Lab Objectives
In this lab, students will gain first-hand experiences on the capability-based access control in
Linux. You will discover the advantages of capabilities and how to use them to achieve the
PoLP (principle of least privileges).
This lab has been modified from the original "Linux Capability Exploration Lab" written by Wenliang Du of Syracuse University.
Copyright 2013 Andrew Kalafut. Copyright ©2006 - 2011 Wenliang Du, Syracuse University. The development of the original
document is/was funded by three grants from the US National Science Foundation: Awards No. 0231122 and 0618680 from
TUES/CCLI and Award No. 1017771 from Trustworthy Computing. Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free
Software Foundation. A copy of the license can be found at http://www.gnu.org/licenses/fdl.html.
2. Lab Setup
The lab is based on Ubuntu 20.04 image installed in Virtual Box. Ubuntu 20.04 doesn’t come
with SELinux. Unfortunately, if you are using Fedora, SELinux will be in our way, preventing
us from doing some of the activities in this lab, so in this case you have to put SELinux to
permissive mode. Later on, we will use SELinux for Mandatory Access Control experiment.
To temporarily put SELinux to permissive mode, issue ’setenforce 0’ as root. To make permissive mode as a startup mode, you
need to modify /etc/selinux/config by changing the line ’SELINUX=enforcing’ to ’SELINUX=permissive’. Note: do not disable
SELinux (only temporarily put it in the permissive mode), otherwise when you enable the SELinux next time, the OS will take
time to re-label the file system for the SELinux context during the boot time.
ps: the ACL lists were covered in the previous lab experiment.
1
3. Lab Tasks
In operating systems, there are many privileged operations that can only be conducted by
privileged users. Examples of privileged operations include configuring network interface card,
backing up all the user files, shutting down the computers, etc. Without capabilities, these
operations can only be carried out by superusers, who often have many more privileges than
what are needed for the intended tasks. Therefore, letting superusers to conduct these
privileged operations is a violation of the Least-Privilege Principle.
Privileged operations are very necessary in operating systems. All setuid programs involve
privileged operations that cannot be performed by normal users. To allow normal users to run
these programs, setuid programs turn normal users into powerful users (e.g. root)
temporarily, even though that the involved privileged operations do not need all the power.
This is dangerous: if the program is compromised, hackers might get the root privilege.
Capabilities divide the powerful root privilege into a set of less powerful privileges. Each of
these privileges is called a capability. With capabilities, we do not need to be a superuser to
conduct privileged operations. All we need is to have the capabilities that are needed for the
privileged operations. Therefore, even if a privileged program is compromised, adversaries
can only get limited power. This way, risk of privileged program can be lowered quite
significantly. Capabilities have been implemented in Linux for quite some time, but they could
only be assigned to processes. Since kernel version 2.6.24, capabilities can be assigned to files
(i.e., programs) and turn those programs into privileged programs. When a privileged program
is executed, the running process will carry those capabilities that are assigned to the program.
In some sense, this is similar to the setuid files, but the major difference is the amount of
privileged carried by the running processes.
First, create a new user and set its password, so run the following commands:
su user1
ping www.google.com
If you look at the file attributes of the program /bin/ping, you will find out that ping is
actually a setuid program with the owner being root, i.e., when you execute ping, your
effective user id becomes root, and the running process is very powerful. If there are
2
vulnerabilities in ping, the entire system can be compromised. The question is whether we can
remove these privileges from ping.
Turn /bin/ping into a non setuid program. This can be done via the following command:
Now, run ping again (as a normal user), and see what happens. Interestingly, the command will
not work. This is because ping needs to open a RAW socket.
1. Explain why this command (setcap cap_net_raw=ep /bin/ping) made ping work again.
2. Why did ping work without the capability before the setuid bit was removed?
In Ubuntu 20.04, you will notice the ping process has no setuid, run the following commands:
3
The first command above: sudo find /usr/bin -perm -4000 shows the programs whose
setuid is set to 1. We notice that ping is not among them. Therefore, we can conclude that on a
modern Linux system this was already granted with "capabilities" when we typed: sudo
getcap /usr/bin/ping
c) Description of Capabilities
a) cap_dac_read_search: Bypass file read permission checks and directory read and execute
permission checks.
To test this command, change captest.c permissions to 000, when we run it as normal user,
4
it shows permission denied. After that we setcap cap_dac_read_search to read command
‘cat’, then run it again, surprisingly, we can read the content of the program. Therefore,
cap_dac_read_search really do bypass the read permission, it can run any program without
read permission. After enabling this capability, it can run any program without read
permission.
b) cap_dac_override: Bypass file read, write, and execute permission checks. (DAC is
abbreviation of "discretionary access control").
First remove the capability that appeared in previous test, try to read the program, you will
find that permission denied, then enable cap_dac_override capability to read
permission ’cat’, and you can successfully read the program.
5
Another example is bypassing edit or write permission for user “ubuntu” after we enable the
capability of cap_dac_override. Before enabling this capability, when we type “vim
/etc/shadow”, we cannot even open the /etc/shadow file (permission denied, since shadow file
has rw for user: root, r for group: shadow, nothing for others). The user “ubuntu” is not in the
group shadow, that is why user “ubuntu” cannot read or access the shadow file.
Now, after we enabled the capability on “vim” command, and then try to open the shadow file.
The following screenshot is the result, we successfully opened the file, and we can also edit
this file. Note that vim.basic is the program (vim is a shortcut to vim.basic).
6
c) cap_chown: Make arbitrary changes to file UIDs and GIDs.
As shown in the screenshot, we want to change the owner of the file captest.c from root to
ubuntu, it turns out that Operation not permitted, then we set cap_chown capability to the
command ‘chown’, after that, we do chown command again, it successfully changes the
owner of the file to ubuntu.
d) Exercises
You can now propose some scenarios where you use more capabilities such as cap_setuid,
cap_kill and cap_net_raw. Note that cap_kill can bypass permission checks for sending kill
signals. cap_net_raw enables normal user to use RAW and PACKET sockets.
Without capabilities, a privileged setuid program can also delete/disable/enable its own
privileges. This is done via the setuid() and seteuid() system calls; namely, a process can change
its effective user id during the run time. The granularity is quite coarse using these system calls,
because you can either be the privileged users (e.g. root) or a non-privileged user. With
capabilities, the privileges can be adjusted in a much finer fashion, because each capability
can be independently adjusted.
To support dynamic capability adjustment, Linux uses a mechanism similar to the setuid
mechanism, i.e., a process carries three capability sets: permitted (P), inheritable (I), and
7
effective (E). The permitted set consists of the capabilities that the process is permitted to use;
however, this set of capabilities might not be active. The effective set consists of those
capabilities that the process can currently use (this is like the effective user uid in the setuid
mechanism). The effective set must always be a subset of the permitted set. The process can
change the contents of the effective set at any time as long as the effective set does not exceed
the permitted set. The inheritable set is used only for calculating the new capability sets after
exec(), i.e., which capabilities can be inherited by the children processes.
Problem:
From classroom, download and compile use_cap.c file. The program can be compiled by
running gcc -o use_cap use_cap.c -lcap. Read the program, grant it the
cap_dac_read_search capability (you will need to be root to do this), and run it as a normal user
(not root).
1. Which attempts to open the file succeeded or failed? Explain why for each.
ubuntu@ubuntu2004:/bin$ su root
Password:
root@ubuntu2004:/bin# gedit use_cap.c
root@ubuntu2004:/bin# gcc -o use_cap use_cap.c -lcap
Assign the cap_dac_read_search capability to the executable file “use_cap”. And login as
normal user, run the program.
root@ubuntu2004:/bin# setcap cap_dac_read_search=eip /bin/use_cap
root@ubuntu2004:/bin# ./use_cap
(a)Open success
(b)Open success
(c)Open success
(d)Open success
(e)Open success
root@ubuntu2004:/bin# su ubuntu
ubuntu@ubuntu2004:/bin$ ./use_cap
(a)Open success
(b)Open failed
(c)Open success
(d)Open failed
(e)Open failed
When observing the code and results, we notice that when the capability is disabled, the
program cannot open the shadow file and shows (b) open failed, then after we enable it, it
can get the capability and it shows (c) open success. If we drop the capability, we get (d)
open failed, and we cannot enable it again after dropping the capability, though, in the code,
even we tried to enable its capability again, (e) still show open failed.
8
2. If we want to dynamically adjust the amount of privileges in ACL based access control,
what should we do? Compared to capabilities, which access control is more convenient to
do so?
ACL is a list of access control entries, which give access permission to a user or group on
a given file or folder. In ACL, if we want to grant permission to other user/group, we always
need to login as root or superuser, and use “chmod” command to grand permission on file
to the aimed user. While by using capabilities, we can bypass some permission check, even
if we were not supposed to have permission on accessing this file. It is more convenient
for normal user since you do not need to ask access permission from root, but it is more
danger.
Yes. After normal user disables a capability A, the attacker can still use the capability A by
enabling it in his malicious code, but if the process deleted the capability, the attacker
cannot use the capability.
4. The same as the previous question, except replacing the buffer-overflow attack with the
race condition attack, Namely, if the attacker exploits the race condition in this program,
can he use the capability A if the capability is disabled? What if the capability is deleted?
If the attacker exploits the race condition in this program, he can still use the capability A
no matter the capability is disabled or deleted. That is because the malicious code will
always run before the capability statement in the race condition attack.
cap_setfcap morgan
cap_dac_override luser
none *
9
Examples of configurations in /etc/security/capability.conf
Conclusion:
Linux Capabilities are used to allow binaries (executed by non-root users) to perform privileged
operations without providing them all root permissions.
10