#!/usr/bin/env python3
"""
Reconnaissance Script for Testing Site Security
Scans for potentially exposed terminate_site and other sensitive files
"""

import requests
import sys
from urllib.parse import urljoin
from concurrent.futures import ThreadPoolExecutor, as_completed
import time

# Configuration
BASE_URL = "https://notillroots.com"  # Change this to your site URL
TIMEOUT = 5
THREADS = 10

# Common backend paths to test
BACKEND_PATHS = [
    "/backend/",
    "/backend/api/",
    "/admin/",
    "/admin/backend/",
    "/wp-admin/",
    "/administrator/",
    "/phpmyadmin/",
    "/.git/",
    "/.env",
    "/config.php",
    "/wp-config.php",
]

# Common sensitive file patterns
SENSITIVE_FILES = [
    "terminate_site_8a3f9b1c2d4e5f6a7b8c9d0e1f2a3b4c.php",
    "terminate_site.php",
    "kill_switch.php",
    "emergency_shutdown.php",
    "destroy.php",
    "wipe.php",
    "config.php",
    ".env",
    ".env.local",
    ".env.production",
    "wp-config.php",
    "database.php",
    "settings.php",
    "admin.php",
    "phpinfo.php",
    "test.php",
    "info.php",
    ".git/config",
    ".gitignore",
    "composer.json",
    "package.json",
    "README.md",
    ".htaccess",
    "robots.txt",
    "sitemap.xml",
]

# Common directory listing patterns
DIRECTORY_PATTERNS = [
    "/backend/",
    "/backend/api/",
    "/uploads/",
    "/files/",
    "/assets/",
    "/images/",
    "/admin/",
    "/includes/",
    "/config/",
    "/database/",
]

class Colors:
    GREEN = '\033[92m'
    RED = '\033[91m'
    YELLOW = '\033[93m'
    BLUE = '\033[94m'
    RESET = '\033[0m'
    BOLD = '\033[1m'

def print_status(message, color=Colors.RESET):
    """Print colored status message"""
    print(f"{color}{message}{Colors.RESET}")

def check_url(url, method='GET'):
    """Check if a URL is accessible"""
    try:
        response = requests.get(url, timeout=TIMEOUT, allow_redirects=False)
        return {
            'url': url,
            'status': response.status_code,
            'size': len(response.content),
            'headers': dict(response.headers),
            'accessible': response.status_code < 400
        }
    except requests.exceptions.Timeout:
        return {'url': url, 'status': 'TIMEOUT', 'accessible': False}
    except requests.exceptions.ConnectionError:
        return {'url': url, 'status': 'CONNECTION_ERROR', 'accessible': False}
    except Exception as e:
        return {'url': url, 'status': f'ERROR: {str(e)}', 'accessible': False}

def test_directory_listing(path):
    """Test if directory listing is enabled"""
    url = urljoin(BASE_URL, path)
    result = check_url(url)
    
    if result['accessible']:
        # Check if response looks like directory listing
        content = requests.get(url, timeout=TIMEOUT).text.lower()
        if any(indicator in content for indicator in ['index of', 'parent directory', '<title>index of']):
            return True, result
    return False, result

def scan_sensitive_files():
    """Scan for sensitive files in common locations"""
    print_status("\n" + "="*70, Colors.BOLD)
    print_status("SCANNING FOR SENSITIVE FILES", Colors.BOLD)
    print_status("="*70 + "\n", Colors.BOLD)
    
    found_files = []
    test_urls = []
    
    # Generate test URLs
    for backend_path in BACKEND_PATHS:
        for sensitive_file in SENSITIVE_FILES:
            # Try direct path
            test_urls.append(urljoin(BASE_URL, backend_path + sensitive_file))
            # Try without leading slash in backend_path
            if backend_path.startswith('/'):
                test_urls.append(urljoin(BASE_URL, backend_path[1:] + sensitive_file))
    
    # Also try root level
    for sensitive_file in SENSITIVE_FILES:
        test_urls.append(urljoin(BASE_URL, "/" + sensitive_file))
    
    # Remove duplicates
    test_urls = list(set(test_urls))
    
    print_status(f"Testing {len(test_urls)} URLs...\n", Colors.BLUE)
    
    # Test URLs with threading
    with ThreadPoolExecutor(max_workers=THREADS) as executor:
        future_to_url = {executor.submit(check_url, url): url for url in test_urls}
        
        for future in as_completed(future_to_url):
            result = future.result()
            url = result['url']
            
            if result['accessible']:
                status_code = result.get('status', 'N/A')
                size = result.get('size', 0)
                
                # Check for suspicious responses
                if status_code == 200 and size > 0:
                    print_status(f"[FOUND] {url} (Status: {status_code}, Size: {size} bytes)", Colors.RED)
                    found_files.append(result)
                elif status_code == 403:
                    print_status(f"[FORBIDDEN] {url} (Status: 403 - File exists but access denied)", Colors.YELLOW)
                elif status_code == 401:
                    print_status(f"[AUTH REQUIRED] {url} (Status: 401)", Colors.YELLOW)
            elif 'TIMEOUT' in str(result.get('status', '')):
                print_status(f"[TIMEOUT] {url}", Colors.YELLOW)
    
    return found_files

def scan_directory_listings():
    """Scan for directory listing vulnerabilities"""
    print_status("\n" + "="*70, Colors.BOLD)
    print_status("SCANNING FOR DIRECTORY LISTING VULNERABILITIES", Colors.BOLD)
    print_status("="*70 + "\n", Colors.BOLD)
    
    vulnerable_dirs = []
    
    for pattern in DIRECTORY_PATTERNS:
        is_listing, result = test_directory_listing(pattern)
        if is_listing:
            print_status(f"[VULNERABLE] Directory listing enabled: {pattern}", Colors.RED)
            vulnerable_dirs.append(result)
        elif result.get('status') == 403:
            print_status(f"[PROTECTED] {pattern} (403 Forbidden)", Colors.GREEN)
        elif result.get('status') == 404:
            print_status(f"[NOT FOUND] {pattern}", Colors.BLUE)
        else:
            print_status(f"[CHECK] {pattern} (Status: {result.get('status', 'N/A')})", Colors.YELLOW)
    
    return vulnerable_dirs

def test_terminate_file_specific():
    """Specifically test for the terminate_site file"""
    print_status("\n" + "="*70, Colors.BOLD)
    print_status("SPECIFIC TEST: terminate_site_8a3f9b1c2d4e5f6a7b8c9d0e1f2a3b4c.php", Colors.BOLD)
    print_status("="*70 + "\n", Colors.BOLD)
    
    terminate_file = "terminate_site_8a3f9b1c2d4e5f6a7b8c9d0e1f2a3b4c.php"
    test_paths = [
        f"/backend/{terminate_file}",
        f"/backend/api/{terminate_file}",
        f"/{terminate_file}",
        f"/admin/{terminate_file}",
        f"/includes/{terminate_file}",
        f"/scripts/{terminate_file}",
    ]
    
    found = False
    for path in test_paths:
        url = urljoin(BASE_URL, path)
        result = check_url(url)
        
        if result['accessible']:
            status = result.get('status', 'N/A')
            size = result.get('size', 0)
            print_status(f"[!!! CRITICAL !!!] {url} is ACCESSIBLE!", Colors.RED + Colors.BOLD)
            print_status(f"    Status: {status}, Size: {size} bytes", Colors.RED)
            found = True
        elif result.get('status') == 403:
            print_status(f"[PROTECTED] {url} (403 Forbidden - File may exist)", Colors.YELLOW)
        elif result.get('status') == 404:
            print_status(f"[NOT FOUND] {url}", Colors.GREEN)
        else:
            print_status(f"[UNKNOWN] {url} (Status: {result.get('status', 'N/A')})", Colors.YELLOW)
    
    return found

def main():
    """Main execution"""
    print_status("\n" + "="*70, Colors.BOLD)
    print_status("SITE RECONNAISSANCE SCANNER", Colors.BOLD)
    print_status(f"Target: {BASE_URL}", Colors.BOLD)
    print_status("="*70 + "\n", Colors.BOLD)
    
    start_time = time.time()
    
    # Run scans
    found_files = scan_sensitive_files()
    vulnerable_dirs = scan_directory_listings()
    terminate_found = test_terminate_file_specific()
    
    # Summary
    elapsed = time.time() - start_time
    print_status("\n" + "="*70, Colors.BOLD)
    print_status("SCAN SUMMARY", Colors.BOLD)
    print_status("="*70, Colors.BOLD)
    print_status(f"Time elapsed: {elapsed:.2f} seconds", Colors.BLUE)
    print_status(f"Sensitive files found: {len(found_files)}", Colors.RED if found_files else Colors.GREEN)
    print_status(f"Directory listings found: {len(vulnerable_dirs)}", Colors.RED if vulnerable_dirs else Colors.GREEN)
    print_status(f"Terminate file accessible: {'YES - CRITICAL!' if terminate_found else 'NO'}", 
                 Colors.RED + Colors.BOLD if terminate_found else Colors.GREEN)
    
    if found_files or vulnerable_dirs or terminate_found:
        print_status("\n[!] SECURITY ISSUES DETECTED - Review findings above", Colors.RED + Colors.BOLD)
    else:
        print_status("\n[✓] No obvious security issues detected", Colors.GREEN)
    
    print()

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print_status("\n\nScan interrupted by user", Colors.YELLOW)
        sys.exit(1)
    except Exception as e:
        print_status(f"\n\nError: {str(e)}", Colors.RED)
        sys.exit(1)

