Linux Privilege Escalation - Sudo for CTF Creators
Sudo
Sudo can have various misconfigurations, which can lead to security vulnerabilities. It is a critical tool that allows authorized users to execute commands as the superuser or another specified user, in accordance with the security policy. These misconfigurations can range from having valid credentials to potential code hijacking.
Sudo permits an authorized user to execute a command as the superuser or another specified user, in accordance with the security policy. The default security policy is defined by the sudoers file, which is configured through /etc/sudoers
or via LDAP.
The security policy dictates how a user may utilize the sudo command.
The sudoers file can be edited using the visudo
command to ensure proper syntax and prevent errors.
Visudo
visudo locks the sudoers file against multiple simultaneous edits, provides basic sanity checks, and checks for parse errors. If the sudoers file is currently being edited you will receive a message to try again later.
visudo parses the sudoers file after the edit and will not save the changes if there is a syntax error.
We can change the text editor for the terminal using this command:
|
|
Learn more about visudo by reading its manual: https://www.sudo.ws/docs/man/visudo.man/
Sudo Syntax
The sudo syntax is the following:
- user host=(user) command
- user host=(user) tag: command
- user host=(user:group) tag: command
- user host=(user:group) tag_1:tag_2: command_1, command_2
- %group host=(user) command
- %group host=(user) tag: command
- %group host=(user:group) tag: command
- %group host=(user:group) tag_1:tag_2: command_1, command_2
Note: You can use ALL to specify the following:
- If ALL is declared in the host field, then ALL hosts will be allowed.
- If ALL is declared in the user field, then ALL users will be allowed.
- If ALL is declared in the group field, then ALL groups will be allowed.
- If ALL is declared in the tag field, it doesn’t end with colons (:) and ALL commands will be allowed.
Sudo Syntax - User Privilege Lines
Examples:
root
ALL=(ALL:ALL) ALL: The rule will apply to (root).- root
ALL
=(ALL:ALL) ALL: This rule applies to all hosts. - root ALL=(
ALL
:ALL) ALL: The root user can run commands as all users. - root ALL=(ALL:
ALL
) ALL: The root user can run commands as all groups. - root ALL=(ALL:ALL)
ALL
: This rule applies to all commands.
This means that our root user can run any command using sudo, as long as they provide their password.
Sudo Syntax - Group Privilege Lines
Names beginning with a ‘%’ indicate group names:
- %admin ALL=(ALL) ALL
- %sudo ALL=(ALL:ALL) ALL
Here, we can see that the admin group can execute any command as any user on any host. Similarly, the sudo group has the same privileges but can execute as any group as well.
Sudo Man Page
Learn more about sudo by reading the documentation: https://www.sudo.ws/docs/man_all/
Privilege Escalation via Known Passwords
If we know the current user’s password we can escalate privileges by switching the root user with sudo:
|
|
Privilege Escalation via Sudo As Another User
We’ll try to escalate from one user to another user. We will start by adding a new user to the system:
|
|
Let’s edit the sudo configuration file with the following command:
|
|
Add the following configuration:
|
|
Switch to the user
:
|
|
List the sudo configuration with the option -l
which means list:
|
|
In GTFOBins, we can see how this can be abused to escalate privileges:
Now let’s execute the program as that specific user:
|
|
The command above spawns a bash
shell as the user.
Privilege Escalation via Abusing Intended Functionality
Edit the sudo configuration file:
|
|
Create the following scripts, the problem with this script is that it doesn’t verify user input:
|
|
Add the rbash
sudo configuration:
|
|
List the sudo configuration:
|
|
If there’s a program that lets we specify its configuration (such as apache2) and prints on screen a syntax error and an invalid command, we may be able to see sensitive information:
|
|
Add this hash to a file:
|
|
Now we can crack the hash with a password recovery tool:
|
|
We know the password, let’s switch to the root user:
|
|
Privilege Escalation via NOPASSWD
Edit the sudo configuration file:
|
|
Sudo configuration might allow a user to execute some command with another user’s privileges without knowing the password.
|
|
List the sudo configuration:
|
|
Run less with sudo:
|
|
Escape from less with:
|
|
Now we will have a root shell:
|
|
Privilege Escalation via SETENV
This directive allows the user to set an environment variable while executing something:
|
|
Edit the sudo configuration file:
|
|
The /etc/sudoers
configuration:
|
|
List the current allowed programs and the default entries:
|
|
Create the directory and the script:
|
|
Add the following code to /opt/scripts/backup.py
:
|
|
It turns out there is a path to exploit backup.py. As shown above, I can pass a $PYTHONPATH into sudo. So what is that variable? When a Python script calls import, it has a series of paths it checks for the module. I can see this with the sys module:
|
|
The first empty line
is important - it is filled at runtime with the current directory of the script (so if the current user could write to /dev/shm
, I could exploit it that way). On this system, $PYTHONPATH is currently empty:
|
|
If I set it and run look at sys.path
again, my addition is added:
|
|
This means that Python will first try to look in the current script directory, then /tmp
, then the Python installs to try to load shutil
. Now we could look for writable directories.
|
|
Generally, we can use /tmp
or /dev/shm
or any other directory that we have write permissions:
|
|
Set a reverse shell:
|
|
Execute the backup.py
which will import our shutil.py
file:
|
|
Receive a connection as root:
|
|
Privilege Escalation via LD_PRELOAD
The environment variable LD_PRELOAD can be used to specify the location of a shared object (.so) file. When this option is enabled, the shared object will be loaded first. We can run code as soon as the object is loaded by building a custom shared object and an init()
function.
Edit the sudo
configuration file:
|
|
This configuration file will be configured as the following:
|
|
LD PRELOAD
will fail if the effective user ID differs from the genuine user ID. Sudo
must use the env_keep
option to retain the LD PRELOAD
environment setting.
List the current allowed programs and the default entries:
|
|
Create a file (preload.c
)
|
|
Add the following code:
|
|
Compile ld_preload.c
to ld_preload.so
:
|
|
Set the LD_PRELOAD
environment variable to the full path of the preload and run any permitted program using sudo
as a result:
|
|
This will elevate the user to UID 0:
|
|
Privilege Escalation via LD_LIBRARY_PATH
The LD_LIBRARY_PATH environment variable specifies which directories should be examined first for shared libraries.
Edit the sudo configuration file:
|
|
The /etc/sudoers
configuration:
|
|
List the current allowed programs and the default entries:
|
|
The ldd
command can be used to print a program’s shared libraries (.so files):
|
|
If we construct a shared library with the same name and set LD_LIBRARY_PATH to its parent directory, the program will load our shared library instead of the one utilized by the program.
This will require some trial and error since some shared objects are used by the program and will result in an error like this one:
|
|
The following code spawns a bash with UID, GID, and EUID as 0 (root):
|
|
Compile the custom shared object with the same name as the one that we want to replace:
|
|
Lastly, we will change the LD_LIBRARY_PATH to our current working directory:
|
|
Since this shared object has a function that is needed by the /usr/sbin/useradd
binary we need to find another shared object that we can use, to do this just keep renaming our custom shared object file libaudit.so.1.c
to names of others shared objects found with GNU linker command ldd /usr/sbin/useradd
. After some trial and error, I found this one:
|
|
The shared object is loaded and now we have a root shell.
Privilege Escalation via Shell Escape Sequences
Edit the sudo configuration file:
|
|
Add this to the /etc/sudoers
configuration:
|
|
List the programs that sudo allows your user to run:
|
|
Visit GTFOBins and search for some of the program names. If the program is listed with “sudo” as a function, we can use it to elevate privileges, usually via an escape sequence.
Choose a program from the list and try to gain a root shell, using the instructions from GTFOBins
.
|
|
Privilege Escalation via Vulnerable Sudo
It is always important to be aware that sudo
vulnerabilities rise sometimes, here is a CVE.
Defense via NOEXEC Tag
Edit the sudo configuration file:
|
|
The NOEXEC option can be utilized to prevent potentially dangerous behavior in certain programs. For instance, some programs, such as less
, can generate other commands from their interface by typing specific inputs.
|
|
Run less with sudo:
|
|
This prevents escapes from less like:
|
|
Sudo Defense
When configuring sudo, it is crucial to carefully define the policy in /etc/sudoers
:
- Avoid using the
NOPASSWD
tag unless the binary or script is not writable by others, does not take user input, or cannot be escaped with sequences. - Do not use
env_keep+=LD_PRELOAD
. - Do not use
env_keep+=LD_LIBRARY_PATH
. - Avoid using the
SETENV
tag. - Ensure sudo is always up to date with the latest version.
- Utilize a password vault or password manager to securely store your passwords.
- Apply the
NOEXEC
tag to binaries that can be exploited.
By following these guidelines, you can enhance the security of your sudo configuration and minimize potential vulnerabilities.