Linux privilege Escalation using the SUID Bit


The SUID bit is a flag on a file which states that whoever runs the file will have the privileges of the owner of the file. So, if you are student and the file is owned by root, then when you run that executable, the code runs with the permissions of the root user. The SUID bit only works on Linux ELF executables, meaning it does nothing if it’s set on a Bash shell script, a Python script file, etc.

We can identify that an executable has been set with SUID by looking at the file’s permissions with ls -la. If there is an s instead of an x in the user permissions, then that file has the SUID bit set.

This is necessary in many system files. For example, if you want to change your password with the passwd utility, then that utility must have permissions to change system files, such as /etc/shadow.

Since normal users do not have those permissions, the utility is configured to have the SUID bit set, and because it is owned by the root user, it has root privileges.

Of course, if you’re able to trick the program with malicious input somehow, then the consequences can be incredibly dangerous.

Finding SUID executables

By using the following command you can enumerate all binaries having SUID permissions:

find / -perm -u=s -type f 2>/dev/null

  • / denotes that we will start from the top (root) of the file system and find every directory
  • -perm denotes that we will search for the permissions that follow:
  • -u=s denotes that we will look for files which are owned by the root user
  • -type states the type of file we are looking for
  • f denotes a regular file, excluding directories and special files
  • 2>/dev/null means we will redirect all errors to /dev/null. In other words, we will ignore all errors.

You will find certain SUID executables in almost all Linux systems, such as: su, mount, passwd, gpasswd, etc. These are there by default and are most likely secure. They will turn up in your search, but we should recognize and ignore them. We want to look for custom SUID executables.

If you aren’t sure which SUID executables are there by default and which are custom, then an easy way is to look for all SUID executables on another (preferably very similar) system. Then you can spot which SUID files exist on the target system, but not on other systems.

Exploitation with command execution

There are numerous programs out there which enable you to execute commands for one reason or another. If the program is owned by root and has the SUID bit enabled, then that makes it trivial to exploit. Since you’re already running the program with root privileges, the commands you run will also be executed with root privileges.

Here are two examples:

find

This will execute echo hello for every file it finds in the current directory:

find . -exec echo hello \;

vim

You can run system commands inside vim.

vim to start the program :!echo hello to run the command

Many other text editors offer similar functionality (nano, less, more, etc)

Exploitation with file writing

If there is a SUID executable which is owned by root and which allows you to write to a file in some way, then it’s possible to get root privileges.

One way to gain a root shell is by adding a new user to /etc/passwd who has the UID 0. Any user with UID 0 is effectively root. We can do this by adding the following line to the passwd file:

root2:WVLY0mgH0RtUI:0:0:root:/root:/bin/bash

Breaking it down:

  • root2 is the username
  • WVLY0mgH0RtUI is the encrypted password we want him to have. Unencrypted, the password is mrcake, in this case
  • 0:0 means the user id and group id are both 0
  • root is a comment field
  • /root is the home directory
  • /bin/bash is the default shell

Note:

Even if the executable didn’t overwrite files, we would easily be able to get a root shell by creating a cron task which will execute any code we want it to. This is achieved by writing a file in /etc/cron.d, though you must ensure it is in the correct format.

Overview

A symlink functions as a shortcut to a destination file or directory. When a program writes to a symlink, then the text will appear in the file which the symlink points to. When a program opens a symlink as a directory, then it reads the contents of the destination directory. If we can use this to our advantage and write to /etc/passwd, for example, then we can escalate our privileges to root.

Let’s say we have a SUID program which copies (and overwrites, if already exists) the contents of one directory to another. Therefore, our plan should be to create a source directory with a malicious passwd file and a destination directory, which is a symlink to /etc. That would allow us to overwrite /etc/passwd with our malicious file.

Create the malicious passwd file

Continuing with our example of a SUID program which copies directories, let’s see how to exploit it.

First let’s create a source directory which will hold our malicious passwd file, which we will use for overwriting /etc/passwd:

mkdir source

Now, create the malicious passwd file, which has an additional UID0 user:

cp /etc/passwd source/passwd
echo 'root2:WVLY0mgH0RtUI:0:0:root:/root:/bin/bash' >> source/passwd

The password for this new root2 user will be mrcake.

We should now create a symlink to the /etc folder. We will call it destination:

ln -s /etc destination

Escalate privileges

Now we can simply run the program with our crafted source and destination directories. /etc/passwd will be overwritten and we will be able to gain root access by doing su root2.

Exploitation with the PATH variable

Introduction to the PATH variable

PATH is an environment variable in Linux and other Unix-like operating systems. If a full path to an executable is not supplied when running a command, then the PATH is used to determine in which directories the executable should be searched. It increases the convenience of such operating systems.

What this means is that when a program does not specify a full path to an externally called executable, then you are in control of where the executable is searched for. When you combine this with a SUID executable, then the results can be dangerous.

Note:

It is assumed that the SUID program sets its own UID (user id) and GID (group id) to 0 (root) before calling the external program. Otherwise, the external program will be called with the privileges of the normal user and the exploit won’t work.

setuid(0);
setgid(0);
system("whoami"); // root, but only because we set UID to 0

Exploitation

If a SUID executable calls another program without a full path set (ps instead of /bin/ps), then the PATH variable is used to decide where to search for the program. So, if we change the PATH variable and point it to a directory we own, and we put a malicious program there, then we can trick the SUID executable into running our malicious code as the superuser.

Let’s use the same code snippet as an example. Let’s say the program is called vulnerable-program, with the following content:

setuid(0);
setgid(0);
system("whoami");

Creating a file which spawns a shell when executed:

echo "/bin/bash" > /tmp/whoami

Allowing other users to execute the file:

chmod 777 /tmp/whoami

Adding our malicious program’s directory to the PATH variable so our malicious file gets located first:

export PATH=/tmp:$PATH

If you want to, you can check the contents of the PATH variable like this:

echo $PATH

Now all we have to do is run the vulnerable SUID executable, and we will have root!

./vulnerable-program

Note:

This does not work if the full path is supplied! For example:

system("/usr/bin/whoami")

Sidenote: SGID bit

It would also be helpful to know about the SGID flag. SGID stands for set group id. It functions just like SUID, except it gives you the group permissions of the file.

We can recognize it by the s character in the group section of a file’s permissions.

The third and final flag you should be aware of is the sticky bit. It’s also called the ‘restricted deletion bit’ because that’s what it does - when it’s set on a directory, then only the owner of the file is allowed to delete a given file.

This is often useful on directories with 777 (everyone is allowed to read and write/delete) permissions. For example, it is set on the /tmp folder.

We can recognize it by the t character in the others section of the permission set.

It is worth knowing about the sticky flag because it can throw a wrench into our plans. In the past, there were often vulnerabilities where a program would write or read files in /tmp. An attacker would quickly swap out the file with a symlink, making the program instead write to any place he wants (like /etc/passwd). To overcome this, the sticky bit was given a special extra restriction:

In directories with the sticky bit set, a program can follow a symlink only if the user of the symlink is the same as the user of the program.

We must keep this in mind when using symlinks for exploitation, as this restriction can stop us dead in our tracks.

Conclusion

We must be especially careful when making custom SUID executables, as one forgotten check or overlooked detail can mean privilege escalation. It should be considered beforehand if there’s any other way to accomplish the task besides crafting a SUID executable.

Additionally, we should know not to give SUID permissions to programs (cp, mv, find) which weren’t designed to be secure when run with the SUID bit.

Heino Sass Hallik