Exploiting Linux Capabilities – Part 1

As I have discussed capabilities in my previous post, there are 40 capabilities, but from an infosec point of view, I will discuss around 20 of them. Fitting writeup for all of them in one post in nearly one post is nearly impossible. I will discuss 4 labs in each post

In this post, I will discuss 2 capabilities related to setuid and setgid. If you want a refresher on them, I have written two posts – Demystifying SUID and SGID bits and Exploiting SUID Binaries to Get Root User Shell

Following are the name and links of the labs I will be discussing today

So let's start off with the first lab


To get the files with at least one capability, you can use getcap recursive search using getcap -r <directory> 2> /dev/null. Redirecting stderr to /dev/null is quite convenient as if the file doesn't have any capability or reading capability is not allowed, it will throw the error

Getting capability recursively in the root directory

Since python interpreter has cap_setuid allowed in the effective set, this means any it can arbitrarily set the user id, even though the user-id is set to 0, you can't set the group id because the process is not running with EUID = 0 and cap_setgid is not allowed. So kernel will drop the action and you will get an "Operation not permitted" error

From the capabilities man page

You can now import the os module and call the setuid function, which will internally call setuid syscall and elevate you to root user with group id same as of current user (i.e student)

Setting UID to 0 and spawning the shell with root user

You can find the reference of same on hacktricks gitbook – https://book.hacktricks.xyz/linux-unix/privilege-escalation/linux-capabilities#cap_setuid


While finding the capabilities recursively in the root directory, I found that again python2 interpreter has cap_setuid set

Getting capability recursively in the root directory

If you look closely, this time it is in the permitted set. So if you try setting UID to 0, where it will fail will be the "Operation not permitted" error. This actually makes sense as the kernel will look for the capabilities in the effective set rather than the permitted set.

setuid function fails as capability is not found in the effective set

However, you can fix this by importing prctl and then transitioning the capability from permitted to effective set. Once this is executed successfully, call os.setuid(0) and this time it will be executed successfully

Successful privilege escalation after permitted => effective transition

In case the capabilities are in the permitted set and prctl is not installed, you can import the ctypes module, load libc and call the prtcl function from that

$ readelf -s /usr/lib/libc.so.6  | grep prctl
   883: 00000000000fedd0   136 FUNC    WEAK   DEFAULT   16 [email protected]@GLIBC_2.2.5
  2126: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS prctl.c
  3738: 00000000000fedd0   136 FUNC    LOCAL  DEFAULT   16 __GI___prctl
  3871: 00000000000ff100    37 FUNC    LOCAL  DEFAULT   16 __GI_arch_prctl
  4467: 00000000000ff100    37 FUNC    LOCAL  DEFAULT   16 __GI___arch_prctl
  4586: 00000000000fedd0   136 FUNC    LOCAL  DEFAULT   16 __prctl
  7594: 00000000000fedd0   136 FUNC    WEAK   DEFAULT   16 prctl
  8096: 00000000000ff100    37 FUNC    WEAK   DEFAULT   16 arch_prctl
  8266: 00000000000ff100    37 FUNC    GLOBAL DEFAULT   16 __arch_prctl
prctl is defined in the libc library


On getting capabilities recursively in the root directory, I found that this time python interpreter has cap_setgid capability set to both effective and permitted set.

Getting capability recursively in the root directory

When a program has cap_setgid capability set in the effective set, you can arbitrarily change the group id when the program is executed. This will not allow you to change the user id.

From the capabilities man page

You can not directly spawn the privileged shell, but perform group-specific action on the files having the same group id as of your current running process, after you call os.setgid() function. This will call setgid() syscall under the hood

List the DAC permissions of /etc/shadow and /etc/passwd files

In the description, it is written that the flag is the hash of the root user. Since there is no write permission to the group in these files, getting a privileged shell is not possible but you can read the content of the shadow file. Since the setgid function require a group id, you can find this information in the /etc/group file

Getting the group id of shadow from /etc/group file

Now I have everything to proceed with, it's time to change the group id to 42 and read the first line from the /etc/shadow file.

When you open the file in python using the open built-in function, it will give you an iterator, to read the first line simply type execute the next(file) function by passing variable to filehandle

Reading the first line from /etc/shadow file using python

So in this case, the hash will start from Yg .... 1. Remember, $1$ is the hash type and $flag$ is the salt, not hash value

For more reference, you can refer to the hacktricks gitbook – https://book.hacktricks.xyz/linux-unix/privilege-escalation/linux-capabilities#cap_setgid


On checking capabilities recursively in the root directory, I found that again the python interpreter was allowed to change the group id.

The flag this time is in the home directory of the root user (i.e /root) but I can't perform any action in the /root directory either ways

Getting capability recursively in the root directory

I found that the current system is running the docker service as the docker socket exists in the /var/run directory and docker CLI is also installed. This means if anyhow I can get run docker container, I can then take over the system

Docker process is running and docker CLI is also installed

I found the docker group can perform read and write actions on the docker socket thus sending commands to the docker service. This isn't a misconfiguration but you can see how running an unintentional application and having another binary to change gid can be a vulnerable vector

Docker socket can be used by the process running with docker group

Let's test all these by listing docker images. If there is no image, it would be then again impossible to escalate to the root user.

Use the /etc/group file to find the group id of docker and spawn a shell from python by setting gid same as of docker.

Docker is working and has an image of ubuntu

Since the docker has an ubuntu image, it is pretty obvious that it will provide a shell to execute commands. Use docker to mount the root in /host directory of the container and spawn a shell. Later you can use chroot utility to get into the root file system of host and perform actions via root user

Running docker container with bind mount and chrooting to root shell

If you are looking for a refresher on how to use chroot, I have already written a post on it – Breaking out of CHROOT Jailed Shell Environment

Gurkirat Singh

Gurkirat Singh

Hey there everyone, I am Gurkirat Singh (aka tbhaxor). I do full-stack development to fund my own learning and experiments. I am a cybersecurity enthusiast and like sharing my knowledge.