Reactor
OS: Linux || Difficulty: Easy
.بسم الله والصلاة والسلام على أشرف خلق الله سيدنا محمد ﷺ وعلى آله وصحبه أجمعين
Let’s dive in
Let’s fire up our favorite Nmap scan again and see which ports are open and what services are running on them.
There’s a Next.js web application running on port 3000.
Let’s begin the web enumeration phase.
So far, it’s just a static page with nothing particularly useful.
Let’s move on to fuzzing and continue gathering information.
Let’s search for virtual hosts to see if there are any additional subdomains.
At the same time, I also started directory fuzzing in the background against the current web application.
At the same time, I opened Wappalyzer to identify the technologies running on the website and check whether there were any interesting version details worth investigating.
I actually found something interesting, the versions of Next.js and React running on the application.
So I left the fuzzing running in the background and started verifying whether this version was actually vulnerable to React-to-Shell or not.
And indeed, it turned out to be vulnerable to React-to-Shell.
When this vulnerability was first disclosed, I saved several resources about it while studying the technique, thinking I might need them someday, and that day finally came.
Just one click … boooom.
We successfully obtained a shell.
The next step was to identify which user we had access as and determine our next target.
After that, we started searching for useful information and sensitive files, and eventually came across reactor.db.
So we downloaded it to our local machine and began analyzing its contents.
Inside the database, we found an admin hash as well as a hash belonging to the engineer user.
The admin hash wasn’t particularly useful for us the real target was the engineer user’s hash.
That’s exactly why identifying our target early on is such an important step.
Now it’s time to crack the hash using Hashcat
We successfully recovered the password, so let’s try using it to log in via SSH.
And here we go, the user flag is ours.
As usual, say it for me.
Initial Enumeration
After gaining access as the engineer user, I started enumerating sudo permissions.
As part of our usual initial enumeration process, we started by checking everything available to us.
We quickly noticed that running sudo -l was not allowed, so we moved on to checking the id output.
the group memberships revealed something interesting:
At first glance, the lxd group looked like the intended privilege escalation vector since members of this group can often abuse LXD containers to gain root access.
I attempted to interact with LXD:
which lxc
lxc image listBut it turned out that the LXD daemon itself was not actually installed or running on the machine, so this path was a dead end.
That meant deeper enumeration was required.
After that, we began enumerating the open ports on the system.
Oh, a new port we don’t know anything about yet.
Let’s do some research and see what we can find.
Port 9229 is commonly associated with the Node.js Inspector Debugger.
To confirm this, I checked the running processes:
Get Veen0o21’s stories in your inbox
Join Medium for free to get updates from this writer.
The output showed:
root1376 ... /usr/bin/node--inspect=127.0.0.1:9229 /opt/uptime-monitor/worker.jsAt this point, the privilege escalation vector became clear.
At this point, the privilege escalation vector became clear.
Now, I had to stop and fully understand what all of this actually meant.
After digging into it, I came across the following:
Understanding the Vulnerability
What is the Node.js Inspector?
The Node.js Inspector is a debugging interface used by developers for:
- debugging applications
- setting breakpoints
- inspecting variables
- executing JavaScript code at runtime
When Node is started with:
node--inspect app.jsit exposes a debugging service over WebSockets.
By default, this service listens on:
127.0.0.1:9229Developers usually assume localhost exposure is safe.
However, this is extremely dangerous when:
- the process runs as
root - i already has local shell access
Because any local user can connect to the debugger and execute arbitrary JavaScript inside the running process.
Since JavaScript can spawn system commands using child_process, this effectively becomes local root RCE.
To communicate with the debugger, I queried the inspector metadata endpoint:
The response returned the active WebSocket debugging endpoint:
{
"title":"/opt/uptime-monitor/worker.js",
"type":"node",
"webSocketDebuggerUrl":"ws://127.0.0.1:9229/8a986380-491d-4e28-973e-191799bddf75"
}This endpoint is required to establish a WebSocket debugging session.
The Exploitation Process
The exploitation process worked like this:
- Open a raw TCP connection to port
9229 - Upgrade the connection to WebSocket
- Communicate using the Chrome DevTools Protocol (CDP)
- Use
Runtime.evaluate - Execute JavaScript inside the root Node.js process
- Spawn system commands through
child_process
Building the Exploit
in the machine, I could not install external npm packages like ws.
Instead, I manually implemented the WebSocket communication using Node’s built-in net module.
The exploit:
- opened a TCP socket
- performed the WebSocket handshake
- manually built WebSocket frames
- executed JavaScript through
Runtime.evaluate
The payload copied /bin/bash into /tmp/rootbash and added the SUID bit.
Exploit Script
The complete exploit script is available on GitHub:
View the exploit script →https://github.com/Veen0o21/Machines/blob/main/Reactor/exploit.js
After running the exploit
I spawned the SUID bash shell:
/tmp/rootbash-pThe -p flag is important because modern bash versions drop privileges unless explicitly told to preserve them.
And just like that… the root flag is ours.
See you in the next machine write-up, Insha’Allah.








