#!/usr/bin/env python3
"""
2025 Critical Vulnerabilities Scanner
Comprehensive scanner for multiple critical CVEs discovered in 2025
"""

import requests
import re
import json
import sys
from urllib.parse import urljoin, urlparse
from typing import Dict, List, Tuple
import urllib3

# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class CVE2025Scanner:
    def __init__(self, target_url: str, timeout: int = 10):
        self.target_url = target_url.rstrip('/')
        self.timeout = timeout
        self.vulnerabilities = []
        self.warnings = []
        self.info = []
        self.headers = {
            'User-Agent': 'CVE2025-Scanner/1.0 (Security Research)'
        }

    def print_banner(self):
        print("=" * 80)
        print("🔴 2025 CRITICAL VULNERABILITIES SCANNER")
        print("=" * 80)
        print(f"🎯 Target: {self.target_url}")
        print("📅 Scanning for: React2Shell, SQL Injection, WordPress, Laravel & more")
        print("=" * 80)
        print()

    # ============== React2Shell CVE-2025-55182 ==============
    def scan_react2shell(self):
        print("[*] Scanning for React2Shell (CVE-2025-55182)...")

        rsc_paths = ['/', '/_next/data', '/api', '/__next_data__']

        for path in rsc_paths:
            url = urljoin(self.target_url, path)

            rsc_headers = {
                **self.headers,
                'RSC': '1',
                'Next-Router-State-Tree': '%5B%22%22%2C%7B%22children%22%3A%5B%22__PAGE__%22%2C%7B%7D%5D%7D%2Cnull%2Cnull%2Ctrue%5D',
                'Accept': 'text/x-component',
            }

            try:
                response = requests.get(url, headers=rsc_headers, timeout=self.timeout, verify=False)

                if 'text/x-component' in response.headers.get('Content-Type', ''):
                    self.vulnerabilities.append({
                        'cve': 'CVE-2025-55182',
                        'name': 'React2Shell',
                        'severity': 'CRITICAL (10.0)',
                        'url': url,
                        'detail': 'RSC endpoint detected'
                    })
                    return True

                if any(m in response.text for m in ['0:', '1:', 'M1:', 'S1:', '__NEXT_DATA__']):
                    self.warnings.append({
                        'type': 'React/Next.js detected',
                        'url': url
                    })

            except Exception:
                pass

        return False

    # ============== SQL Injection Tests ==============
    def scan_sql_injection(self):
        print("[*] Scanning for SQL Injection vulnerabilities...")

        # Common SQL injection payloads
        payloads = [
            "1' OR '1'='1",
            "admin' --",
            "' OR 1=1--",
            "1' AND SLEEP(5)--",
            "' UNION SELECT NULL--"
        ]

        # Test common parameters
        test_endpoints = [
            '/login.php',
            '/admin/login.php',
            '/user/login',
            '/api/login',
            '/index.php',
            '/search.php'
        ]

        vulnerable = False

        for endpoint in test_endpoints:
            url = urljoin(self.target_url, endpoint)

            for payload in payloads[:2]:  # Test only first 2 payloads to avoid detection
                try:
                    # Test GET
                    test_url = f"{url}?id={payload}"
                    response = requests.get(test_url, timeout=5, verify=False, allow_redirects=False)

                    # Look for SQL error messages
                    sql_errors = [
                        'sql syntax',
                        'mysql_fetch',
                        'mysql_num_rows',
                        'mysqli',
                        'postgresql',
                        'sqlite',
                        'ora-',
                        'microsoft sql',
                        'syntax error',
                        'unclosed quotation'
                    ]

                    response_lower = response.text.lower()
                    if any(error in response_lower for error in sql_errors):
                        self.vulnerabilities.append({
                            'cve': 'SQL Injection',
                            'name': 'SQL Injection',
                            'severity': 'CRITICAL',
                            'url': url,
                            'detail': f'SQL error detected with payload: {payload}'
                        })
                        vulnerable = True
                        break

                except Exception:
                    pass

            if vulnerable:
                break

        return vulnerable

    # ============== WordPress Scanner ==============
    def scan_wordpress(self):
        print("[*] Scanning for WordPress vulnerabilities...")

        # Check if WordPress
        wp_paths = [
            '/wp-admin/',
            '/wp-login.php',
            '/wp-content/',
            '/wp-includes/'
        ]

        is_wordpress = False

        for path in wp_paths:
            url = urljoin(self.target_url, path)
            try:
                response = requests.get(url, timeout=self.timeout, verify=False)
                if response.status_code == 200 or 'WordPress' in response.text:
                    is_wordpress = True
                    self.info.append('WordPress detected')
                    break
            except Exception:
                pass

        if not is_wordpress:
            return False

        # Check for vulnerable plugins
        vulnerable_plugins = {
            'database-for-contact-form-7': 'CVE-2025-7384 (CVSS 9.8) - RCE',
            'w3-total-cache': 'CVE-2025-9501 (CVSS 9.0) - RCE',
            'wp-ghost': 'CVE-2025-26909 - LFI to RCE',
            'ai-engine': 'Critical RCE vulnerability'
        }

        for plugin, cve_info in vulnerable_plugins.items():
            url = urljoin(self.target_url, f'/wp-content/plugins/{plugin}/')
            try:
                response = requests.get(url, timeout=5, verify=False)
                if response.status_code == 200:
                    self.vulnerabilities.append({
                        'cve': cve_info.split()[0],
                        'name': f'WordPress Plugin: {plugin}',
                        'severity': 'CRITICAL',
                        'url': url,
                        'detail': cve_info
                    })
            except Exception:
                pass

        # Check WordPress version
        try:
            response = requests.get(self.target_url, timeout=self.timeout, verify=False)
            wp_version = re.search(r'wp-includes.*?ver=([0-9.]+)', response.text)
            if wp_version:
                self.info.append(f'WordPress version: {wp_version.group(1)}')
        except Exception:
            pass

        return len(self.vulnerabilities) > 0

    # ============== Laravel Scanner ==============
    def scan_laravel(self):
        print("[*] Scanning for Laravel vulnerabilities...")

        # Check if Laravel
        laravel_indicators = [
            '/laravel',
            'laravel_session',
            'XSRF-TOKEN',
            'Laravel',
            'Illuminate'
        ]

        is_laravel = False

        try:
            response = requests.get(self.target_url, timeout=self.timeout, verify=False)

            # Check cookies and headers
            cookies_str = str(response.cookies)
            headers_str = str(response.headers)

            if any(ind in response.text or ind in cookies_str or ind in headers_str
                   for ind in laravel_indicators):
                is_laravel = True
                self.info.append('Laravel framework detected')

        except Exception:
            pass

        if not is_laravel:
            return False

        # Check for debug mode (XSS vulnerability in Laravel 11.x)
        try:
            # Try to trigger an error
            test_url = urljoin(self.target_url, '/this-route-does-not-exist-test-12345')
            response = requests.get(test_url, timeout=self.timeout, verify=False)

            if 'Whoops' in response.text or 'DebugBar' in response.text:
                self.vulnerabilities.append({
                    'cve': 'Laravel Debug Mode',
                    'name': 'Laravel Debug Mode Enabled',
                    'severity': 'HIGH',
                    'url': self.target_url,
                    'detail': 'Debug mode enabled - XSS vulnerability in Laravel 11.9.0-11.35.1'
                })

        except Exception:
            pass

        # Check for exposed .env file
        env_url = urljoin(self.target_url, '/.env')
        try:
            response = requests.get(env_url, timeout=5, verify=False)
            if response.status_code == 200 and 'APP_KEY' in response.text:
                self.vulnerabilities.append({
                    'cve': 'Laravel APP_KEY Exposure',
                    'name': 'Exposed .env file',
                    'severity': 'CRITICAL',
                    'url': env_url,
                    'detail': 'APP_KEY exposed - leads to RCE via deserialization'
                })
        except Exception:
            pass

        return len(self.vulnerabilities) > 0

    # ============== FreePBX CVE-2025-57819 ==============
    def scan_freepbx(self):
        print("[*] Scanning for FreePBX (CVE-2025-57819)...")

        freepbx_paths = [
            '/admin/config.php',
            '/freepbx',
            '/recordings'
        ]

        for path in freepbx_paths:
            url = urljoin(self.target_url, path)
            try:
                response = requests.get(url, timeout=self.timeout, verify=False)
                if 'FreePBX' in response.text or 'Asterisk' in response.text:
                    self.vulnerabilities.append({
                        'cve': 'CVE-2025-57819',
                        'name': 'FreePBX Authentication Bypass',
                        'severity': 'CRITICAL (10.0)',
                        'url': url,
                        'detail': 'FreePBX detected - check for versions 15, 16, 17'
                    })
                    return True
            except Exception:
                pass

        return False

    # ============== Framework Detection ==============
    def detect_technologies(self):
        print("[*] Detecting web technologies...")

        try:
            response = requests.get(self.target_url, timeout=self.timeout, verify=False)

            # Server header
            server = response.headers.get('Server', '')
            if server:
                self.info.append(f'Server: {server}')

            # Powered-by header
            powered_by = response.headers.get('X-Powered-By', '')
            if powered_by:
                self.info.append(f'Powered-By: {powered_by}')

            # Check content
            content = response.text.lower()

            technologies = {
                'react': ['react', '_next'],
                'django': ['django', 'csrftoken'],
                'php': ['php', '.php'],
                'apache': ['apache'],
                'nginx': ['nginx'],
                'iis': ['iis', 'microsoft'],
            }

            detected = []
            for tech, patterns in technologies.items():
                if any(pattern in content or pattern in str(response.headers).lower()
                       for pattern in patterns):
                    detected.append(tech)

            if detected:
                self.info.append(f"Technologies: {', '.join(detected)}")

        except Exception as e:
            pass

    # ============== Security Headers Check ==============
    def check_security_headers(self):
        print("[*] Checking security headers...")

        try:
            response = requests.get(self.target_url, timeout=self.timeout, verify=False)

            security_headers = {
                'X-Frame-Options': 'Clickjacking protection',
                'X-Content-Type-Options': 'MIME type sniffing protection',
                'X-XSS-Protection': 'XSS protection',
                'Strict-Transport-Security': 'HTTPS enforcement',
                'Content-Security-Policy': 'Content security policy',
                'X-Permitted-Cross-Domain-Policies': 'Cross-domain policy'
            }

            missing_headers = []

            for header, description in security_headers.items():
                if header not in response.headers:
                    missing_headers.append(f'{header} ({description})')

            if missing_headers:
                self.warnings.append({
                    'type': 'Missing Security Headers',
                    'details': missing_headers
                })

        except Exception:
            pass

    # ============== MAIN SCAN ==============
    def run_scan(self):
        self.print_banner()

        # Technology detection
        self.detect_technologies()
        print()

        # Run all scans
        scans = [
            ('React2Shell', self.scan_react2shell),
            ('SQL Injection', self.scan_sql_injection),
            ('WordPress', self.scan_wordpress),
            ('Laravel', self.scan_laravel),
            ('FreePBX', self.scan_freepbx),
        ]

        for scan_name, scan_func in scans:
            try:
                scan_func()
            except Exception as e:
                print(f"[!] Error in {scan_name} scan: {str(e)}")

        # Security headers
        self.check_security_headers()

        # Print results
        self.print_results()

    def print_results(self):
        print("\n" + "=" * 80)
        print("📊 SCAN RESULTS")
        print("=" * 80)

        # Info
        if self.info:
            print("\n🔵 INFORMATION:")
            for info in self.info:
                print(f"  ℹ️  {info}")

        # Warnings
        if self.warnings:
            print("\n🟡 WARNINGS:")
            for warning in self.warnings:
                if isinstance(warning, dict):
                    print(f"  ⚠️  {warning.get('type', 'Warning')}")
                    if 'url' in warning:
                        print(f"     URL: {warning['url']}")
                    if 'details' in warning:
                        for detail in warning['details']:
                            print(f"     - {detail}")
                else:
                    print(f"  ⚠️  {warning}")

        # Vulnerabilities
        if self.vulnerabilities:
            print("\n🔴 VULNERABILITIES DETECTED:")
            for vuln in self.vulnerabilities:
                print(f"\n  ❌ {vuln['name']}")
                print(f"     CVE: {vuln['cve']}")
                print(f"     Severity: {vuln['severity']}")
                print(f"     URL: {vuln['url']}")
                print(f"     Detail: {vuln['detail']}")

        # Final verdict
        print("\n" + "=" * 80)
        if self.vulnerabilities:
            print("⚠️  VERDICT: VULNERABILITIES FOUND!")
            print("\n📋 RECOMMENDATIONS:")
            print("  1. Review all detected vulnerabilities immediately")
            print("  2. Update all frameworks and plugins to latest versions")
            print("  3. Apply security patches for detected CVEs")
            print("  4. Implement Web Application Firewall (WAF)")
            print("  5. Enable security headers")
            print("  6. Perform detailed manual security audit")
            print("\n🔗 Full report: /var/www/html/critical_vulnerabilities_2025.md")
        else:
            print("✅ VERDICT: No obvious critical vulnerabilities detected")
            print("\n⚠️  Note: This is an automated scan. Manual verification recommended.")
            print("   Consider professional penetration testing for comprehensive assessment.")

        print("=" * 80)

        # Summary
        print(f"\n📈 SUMMARY:")
        print(f"   Vulnerabilities: {len(self.vulnerabilities)}")
        print(f"   Warnings: {len(self.warnings)}")
        print(f"   Info: {len(self.info)}")
        print()


def main():
    if len(sys.argv) < 2:
        print("Usage: python3 2025_vulnerabilities_scanner.py <target_url>")
        print("Example: python3 2025_vulnerabilities_scanner.py http://example.com")
        sys.exit(1)

    target = sys.argv[1]

    # Validate URL
    if not target.startswith(('http://', 'https://')):
        target = 'http://' + target

    scanner = CVE2025Scanner(target)
    scanner.run_scan()


if __name__ == "__main__":
    main()
