Exploiting Linux Capabilities – Part 3

In the previous posts, I have discussed how DAC permissions can be bypassed by the respective capabilities and if they are set on unwanted files like text editors and program interpreters like python. If you haven't read those posts, I would recommend you to first read them and then come here – Understanding Linux Capabilities and Exploiting Linux Capabilities – Part 2

In this post, I will be discussing sysadmin level capabilities like mounting files, changing system time, killing process and changing file ownership. To demonstrate these, I will be using the following labs from the pentester academy

If you want to learn the Linux Privilege Escalation from start, I would recommend you to check out my Linux Privilege Escalation Series

So let's begin...


When I looked for binaries with at least one capability recursively in the root directory and found that python2.7 binary has cap_sys_admin capability set in the both effective and permitted sets

Getting the binaries with capabilities, recursively in the root directory

When a program is running with cap_sys_admin capability, it can perform all the sysadmin related tasks like mounting file systems and etc. The capability is overloaded with actions. You can check its man page

From the man page of capabilities

So in this case, since I can't directly update the password in the /etc/passwd file, but I can perform a bind mount. Copy the /etc/passwd file to the current working directory (/home/student) and make the changes in the root user password.

You can generate a new password from the OpenSSL program as shown below

Updating root user password in the local passwd file

After this is done, I have copied the exploit code from hacktricks gitbook and saved it as exploit.py in the lab – https://book.hacktricks.xyz/linux-unix/privilege-escalation/linux-capabilities#cap_sys_admin

from ctypes import *
libc = CDLL("libc.so.6")
libc.mount.argtypes = (c_char_p, c_char_p, c_char_p, c_ulong, c_char_p)
MS_BIND = 4096  # defined in /usr/include/sys/mount.h:55
source = b"/home/student/passwd"
target = b"/etc/passwd"
filesystemtype = b"none"
options = b"rw"
mountflags = MS_BIND
libc.mount(source, target, filesystemtype, mountflags, options)
Exploit code for a bind mount

Run the exploit code and check the first line of the /etc/passwd file. The password will be updated by the one created in the /home/student/passwd

Running the python exploit

Perform switch user action with -l option to also log in as root user and land in its home directory (i.e /root)

Login to root user using "password"

To get a refresher on su command and /etc/passwd or /etc/shadow file, I recommend you read my posts – Understanding Linux File Permissions and Exploiting File Permissions Misconfigurations


In this lab, while searching for programs with capabilities, I found that date binary has cap_sys_time capability

Getting the binaries with capabilities, recursively in the root directory

Usually, if a program is running as a normal user and tries to change the date, the function fails with the "Operation not permitted" message

$ date +%T -s "00:00:30"
date: cannot set date: Operation not permitted
date command failed while setting changing the system flag

However, if the program has cap_sys_time, it can go ahead and change the system date (hardware clock)

From the man page of capabilities

You can't directly escalate to privileges using this capability. If there any misconfigured cron job is running, you can modify the script content and change the date and time to execute it immediately

I found that there is a cron job running at 23:00 time each day. This executes a script from /tmp/archive-log.sh

Cronjob running /tmp/archive-log.sh file at 23:00 each day

Luckily there is no file in the /tmp/ directory. So, I create a malicious file setting SUID bit on the /bin/bash program. To know more about how SUID and SGID works and how you can exploit these misconfigurations, I recommend you to read these two posts first – Demystifying SUID and SGID bits and Exploiting SUID Binaries to Get Root User Shell

Creating malicious binary in /tmp/archive-log.sh

You can copy the above script from below and paste it in /tmp/archive-log.sh file


chmod +s /bin/bash > /tmp/done 2> /tmp/error
Script to set suid bit on /bin/bash program

The current time is 00:08:41 and crontab will execute in 22:51:19. Well, I don't think no one would have that much patience. Since date binary can change the system time. I have managed to change it to 22:59:59, which is 1 sec before the time script will execute

After you see the /tmp/done file, it means the script executed successfully and you can go ahead get a privileged shell using the bash -p command

Escalating to the root user from bash privileged shell

LAB: The Basics: CAP_KILL

This time I found that the python interpreter has cap_kill capabilities in both permitted and effective sets

Getting the binaries with capabilities, recursively in the root directory

Usually, a user can kill the process created by the same uid. However, if a program has cap_kill capabilities in the current logged in user session, it can kill any process including the on which are started by another user

From the man page of capabilities

You can not directly escalate to the root user. However, if a service like web services or cron jobs are running that automatically restarts when get kill. This is a typical scenario when a web app is deployed to production.

In this lab, I can see the nginx server is running with root privileges. Since I don't have permission to restart the server gracefully, if it restarts automatically after killing the new config will be processed.

In this case, I can write to the nginx config file located at /etc/nginx/nginx.conf

nginx server is running and the config file is writable

Add the following code in the config file under the HTTP block. When the server will restart, it will open a port 8080 and when you will make a curl request to this port, it serves as static content and you can read the file like you are accessing a resource on the web http://localhost:8080/<file-name>

server {
  listen 8080;
  location / {
    root /root;
    autoindex on;
nginx server directory listing config

Use python to send SIGKILL to the nginx process group using the os.killpg function from the os module

Killing the process group corresponds to nginx 

As expected, the nginx server restart and now port 8080 is also open. This means I can now go ahead the read contents of the root directory.

The server restarted and the 8080 port is now open

I found that the flag file is located in the /root/flag file thus can be retrieved via making a curl request to http://localhost:8080/flag instead of /root/flag

Retrieving the flag

LAB: The Basics: CAP_CHOWN

In this lab, I found that the python has cap_chown capability in both permitted and effective set

Getting the binaries with capabilities, recursively in the root directory

When a program is running with cap_chown capability in the effective set, it can change the user or/and group ownership of any file on the system. This is directly linked to privilege escalation as you can change the ownership of the shadow file and update the new password

From the man page of capabilities

The user id and group id of the currently logged in user are 1000. I have used to call chown syscall from os module to change the ownership of the /etc/shadow file to 1000:1000

Changing the ownership of the /etc/shadow file

Now I can create the password using the OpenSSL utility (shown below). Since now I own that file, I can open and update the password in a file using vim editor

Logging in as root user and retrieve the flag

To know more about Linux file permissions and ownership, I would recommend you to also read these two posts – Understanding Linux File Permissions and Exploiting File Permissions Misconfigurations

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.