libcap-ng

   

Up

Latest Release is 0.8.4
Dec 20, 2023:

libcap-ng-0.8.4.tar.gz
libcap-ng-0.8.3.tar.gz
ChangeLog


Of interest:
Patches to drop privs
Testing libcap-ng
Fedora Project

Browse code at github
git clone https://github.com/stevegrubb/libcap-ng.git
 
The libcap-ng library is intended to make programming with posix capabilities much easier than the traditional libcap library. It includes utilities that can analyse all currently running applications and print out any capabilities and whether or not it has an open ended bounding set. An open bounding set without the securebits "NOROOT" flag will allow full capabilities escalation for apps retaining uid 0 simply by calling execve.

The included utilities are designed to let admins and developers spot apps from various ways that may be running with too much privilege. For example, any investigation should start with network facing apps since they would be prime targets for intrusion. The netcap program will check all running apps and display the results. Sample output from netcap:

ppid  pid   acct       command          type port  capabilities
1     2295  root       nasd             tcp  8000  full
2323  2383  root       dnsmasq          tcp  53    net_admin, net_raw +
1     2286  root       sshd             tcp  22    full
1     2365  root       cupsd            tcp  631   full
1     2286  root       sshd             tcp6 22    full
1     2365  root       cupsd            tcp6 631   full
2323  2383  root       dnsmasq          udp  53    net_admin, net_raw +
2323  2383  root       dnsmasq          udp  67    net_admin, net_raw +
1     2365  root       cupsd            udp  631   full

But assuming someone was successful in getting into your system and only has partial capabilities, what might be the next targets to gain full privs? The pscap program will show you all apps currently running on the system that have privileges. Ideally, all apps running as uid 0 should drop privileges. Some can't for good reasons as explained later. But many can.

If for some reason you feel that its too hard or app developers are unwilling to change, the admin can set file based capabilities, using filecap, if the file system has extended attributes and the kernel supports file system based capabilities. It can also search out files on your system that have filesystem based capabilities.

I think one of the intentions of file system based capabilities was to allow admins to take control of their security risk profile and drop privileges of apps on their system independent of what application developers do. I suspect that the low rate of adoption for dropping privileges is because the old API made it tedious to do any task and therefore app developers just don't use it. How many apps have you seen that says you need to be root to use this program? This is because its just 1 line of code to check if you are the root user. The programmer probably knew that a specific capability was needed, but chose to take the shortcut instead. I wanted to change that by making an easy to use API. Its easier to accept a 3-4 line patch than one that adds some 20 lines of code.

As an application developer, there are probabaly 6 use cases that you are interested in: drop all capabilities, keep one capability, keep several capabilities, check if you have any capabilities at all, check for certain capabilities, and retain capabilities across a uid change. I'll show how easy it is to do each of these below using libcap-ng (and now in python):

1) Drop all capabilities
     capng_clear(CAPNG_SELECT_BOTH);
     capng_apply(CAPNG_SELECT_BOTH);

2) Keep one capability
     capng_clear(CAPNG_SELECT_BOTH);
     capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_CHOWN);
     capng_apply(CAPNG_SELECT_BOTH);

3) Keep several capabilities
     capng_clear(CAPNG_SELECT_BOTH);
     capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_SETUID, CAP_SETGID, -1);
     capng_apply(CAPNG_SELECT_BOTH);

4) Check if you have any capabilities
     if (capng_have_capabilities(CAPNG_SELECT_CAPS) > CAPNG_NONE)
         do_something();

5) Check for certain capabilities
     if (capng_have_capability(CAPNG_EFFECTIVE, CAP_CHOWN))
         do_something();

6) Retain capabilities across a uid change
     capng_clear(CAPNG_SELECT_BOTH);
     capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_CHOWN);
     if (capng_change_id(99, 99, CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING))
         error();


Now, isn't that a lot simpler? Note that the last example takes about 60 lines of code using the older capabilities library. As of the 0.6 release, there is a m4 macro file to help adding libcap-ng to your autotools config system. In configure.ac, add LIBCAP_NG_PATH. Then in Makefile.am locate the apps that link to libcap-ng, add $(CAPNG_LDADD) to their _LDADD entries. And lastly, surround the optional capabilities code with #ifdef HAVE_LIBCAP_NG.

One aspect of this library that makes it more complete is that it treats the bounding set as if it were another kind of capability set. The same functions that take effective, permitted, or inheritable also take bounding_set. But sometimes you don't want to touch the bounding set, so the API allows you to select between the traditional capabilities, the bounding set, or both. One thing to note, if you want to change the bounding set, you must have SETPCAP capability. You can drop traditional capabilities at any time even without the SETPCAP capability. Read more about this in the "capabilities (7)" man page.

So what do we do with all this new ability to use posix capabilities in just a couple lines of code? We should patch everything to minimize capabilities. :-) See link above for some preliminary patches that demonstrate dropping privs for common packages.


See the picture above. There are 3 kinds of apps. The first is like sshd, crond, xinetd, or gdm. They spawn apps for various users and you never know what that user will need. These can and should run with full capabilities. The second kind of app is one that does not need full privs to do its job but yet its running as the root uid. This is really the prime target for libcap-ng. The last kind of app is the ones that run on a non-root account and have dropped all privs. These we do not need to worry about.

The image above shows the current situation in Linux post 2.6.26 kernel. Notice the yellow colored daemon. If apps are not clearing their bounding set and retaining the root uid and if any attack on these apps are successful, the attacker can regain full privs just by calling execve. What we really want is shown in the picture below.


In this picture, we see that the bounding set is being cleared so that attacks against apps with partial capabilities (the yellow daemon) stay partial capabilities. Sometimes apps have a legitimate reason for allowing child processes to regain privs, so the libcap-ng library allows for this, too.

It is possible to create a hardened system using capabilities. If we patch all daemons except the 2-3 login/cron daemons to drop privs, then those apps running as root are ineffective attack targets. But they still have uid 0, which typical system installation allows root to do things. For example, /bin/sh is 0755 and /bin is also 0755 perms. A disarmed root process can still trojan a system. But what if we got rid of all the read/write permissions for root? Something like this:

echo "Hardening files..."
find / -type f -perm /00700 -a -uid 0 -exec chmod u-wrx {} \; 2>/dev/null
find / -type f -perm /00070 -a -gid 0 -exec chmod g-wrx {} \; 2>/dev/null
echo "Hardening directories..."
find / -type d -perm /00200 -a -uid 0 -exec chmod u-w {} \; 2>/dev/null
find / -type d -perm /00020 -a -gid 0 -exec chmod g-w {} \; 2>/dev/null
echo "Correcting a couple things..."
find /sbin -type f -perm /00000 -a -uid 0 -exec chmod u+x {} \; 2>/dev/null
find /usr/sbin -type f -perm /00000 -a -uid 0 -exec chmod u+x {} \; 2>/dev/null

Would this system still work? (Hopefully you try this in a VM first.) The answer is for the most part, yes. The only issue I know of is the /etc/resolve.conf file needing to be written if dhcp is being used. The reason that the system still works is because the admin logins in as root and gets the DAC_OVERRIDE capability. DAC_OVERRIDE allows the reading or writing of any file on the system regardless of the ownership or permissions. Sshd calls pam for authentication, which in turn runs a setuid helper that has DAC_OVERRIDE so it can read the shadow file. Changing your password still works since pam's setuid helper is used.

Any daemon that is running should not have the DAC_OVERRIDE capability. This way even if that daemon is compromised, it cannot do too much to the system. It cannot read /etc/shadow since the file's perms are now 0000. It cannot install binaries since the directory perms are 0005 root root. IOW, root daemons are reduced to being a common user with regards to reading/writing files.

So if you want to go down this path of hardening your system, you need to be very careful about which apps have DAC_OVERRIDE. These apps will have the ability to read/write files anywhere on the system no matter what uid it has. They will become the attack targets for the system. If you patch an app to drop capabilities and this one is required, you might want to consider whether or not the app needs a redesign. In many cases its a matter of creating a directory owned by the application that's writable by its uid and then move whatever its writing/reading to that directory. Be very careful about giving out DAC_OVERRIDE.