Exploiting Linux Capabilities – Part 4

Learn about Linux file capabilities like cap_fowner, cap_setfcap, cap_dac_override and cap_linux_immutable and how to exploit these in order to read privileged files or get the root user shell

Exploiting Linux Capabilities – Part 4

In the previous posts, I have discussed the working Linux capabilities and how to exploit capabilities that sysadmin often requires. If you want to learn Linux privilege escalation from starting, here is the list of all the topics I have published so far – https://tbhaxor.com/linux-privilege-escalation/.

In this post, I will again discuss the labs to cover more about file related capabilities. There are two posts on the same topic – Part 1 and Part 2 on exploiting the Linux capabilities.

So let's begin ...

LAB: The Basics: CAP_FOWNER

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

Getting capable binaries recursively in the root directory

When a program is running with cap_fowner capabilities, it bypasses all the current uid and file owner uid match required for all the operations excluding what is required for cap_dac_read_search and cap_dac_override capabilities (discussed in part 2 of exploiting Linux capabilities). These are calling syscalls like chmod and utime

From the man pages of capabilities

If any program that can call chmod syscall has this capability set, it could lead to direct privilege escalate. All I need to do is set the read-write permissions on the /etc/passwd file

Changing the ownership of /etc/passwd file

Since now the file is world-writable, I can change the password of the root user in the /etc/passwd file using the vim spawned by the current user (i.e student). Later perform switch user with -l flag to login and land in the home directory of the root user

Updating password in /etc/passwd and perform root user login

LAB: The Basics: CAP_SETFCAP

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

Getting capable binaries recursively in the root directory

When a program is running with cap_setfcap capability in the effective set, it can set any capability on any file. This could lead to a direct system takeover, as the program can go ahead and set cap_setuid on the program that can call setuid syscall to spawn a privileged shell

I have retrieved the following exploit code from hacktricks. It will set cap_setuid+ep capability to any file passed as the first argument to the script

import ctypes, sys

#Load needed library
#You can find which library you need to load checking the libraries of local setcap binary
# ldd /sbin/setcap
libcap = ctypes.cdll.LoadLibrary("libcap.so.2")

libcap.cap_from_text.argtypes = [ctypes.c_char_p]
libcap.cap_from_text.restype = ctypes.c_void_p
libcap.cap_set_file.argtypes = [ctypes.c_char_p,ctypes.c_void_p]

#Give setuid cap to the binary
cap = 'cap_setuid+ep'
path = sys.argv[1]
print(path)
cap_t = libcap.cap_from_text(cap)
status = libcap.cap_set_file(path,cap_t)

if(status == 0):
    print (cap + " was successfully added to " + path)
Exploit code from hacktricks gitbook

In this case, I will set this capability on the python interpreter. The cap_set_file function in libc only accepts the path of the actual file. So if you will give the path of symlink it will throw an error

Setting cap_setuid+ep capability on python file

Since python binary now has cap_setuid capability set, I can perform the os.setuid function and spawn the root user shell and read-protected files

Spawning root user shell from python

LAB: The Basics: CAP_DAC_OVERRIDE III

In my last posts, I have discussed cap_dac_override capability in detail. It allows you to perform read/write operations on any file and execute permission of directories. In this lab, I found an interesting program that has this capability.

This program is a linker – x86_64-linux-gnu-ld.bfd

Getting capable binaries recursively in the root directory

I learnt this technique from one of the CTF writeups from attackdefense's lab – https://happybear.medium.com/sincon-wonderland-ctf-privilege-escalation-points-200-6bf3aaaa330

You can read files by fooling the linker to interpret them as binary output from the compiler.

Reading the flag file

The explanation of the above command is as follows

  • -r generate the reallocatable output, otherwise, the linker will not able to find the _start section. This flag is optional
  • -b binary tells the linker to treat the input file as binary output from the assembler. This is required because if it's omitted, the linker will treat the input file as a script
  • /root/flag is the input file
  • -o flag.o tells the linker where to output the file

LAB: CAP_LINUX_IMMUTABLE

In this lab, I found that the python interpreter has cap_linux_immutable capability in both effective and privileged sets

Getting capable binaries recursively in the root directory

Generally, all the files that a current user owns or are world-writable can be deleted or modified by the user. But in some situations to prevent accidental deletion of the file, it is recommended to make that file immutable. This means even if you own a file, you can not delete it or update its contents, but you can read the file without any issue. To set or unset this flag, you need to run the chattr command via root user.

However, if a program is running with cap_linux_immutable capability in the effective set, it can modify the contents of the immutable file

From the man page of capabilities

I see there is a file named backup.sh and same file is executed via root user every minute from a cronjob

A cron job is running the backup script every minute

Directly I can't update the file content as the file is immutable and unsetting the immutable attribute seems impossible

Immutable files are not writable

Since python has the file capability to change the contents of an immutable file, I got the exploit code from hacktricks gitbook which does exactly the same.

This will set suid bit on /bin/bash file and I get privileged shell using /bin/bash -p flag

import fcntl
import os
import struct

FS_APPEND_FL = 0x00000020
FS_IOC_SETFLAGS = 0x40086602

fd = os.open('/home/student/backup.sh', os.O_RDONLY)
f = struct.pack('i', FS_APPEND_FL)
fcntl.ioctl(fd, FS_IOC_SETFLAGS, f)

f=open("/home/student/backup.sh",'a+')
f.write('chmod +s /bin/bash\n')
f.close()
Exploit code from hacktricks gitbook

After running the exploit code on the /home/student/backup.sh I was able to append malicious code in the backup.sh file

Python exploit writing to immutable file

On the next hit, I was able to spawn the shell as root user. If you want to learn about how suid works and how it can be exploited, here are my two posts – Demystifying SUID and SGID bits and Exploiting SUID Binaries to Get Root User Shell

Spawn privileged bash shell