mirror of
https://github.com/outbackdingo/OpCore-Simplify.git
synced 2026-01-27 10:19:49 +00:00
351 lines
13 KiB
Python
351 lines
13 KiB
Python
from Scripts import run
|
|
from Scripts import utils
|
|
import platform
|
|
import json
|
|
|
|
os_name = platform.system()
|
|
|
|
class WifiProfileExtractor:
|
|
def __init__(self):
|
|
self.run = run.Run().run
|
|
self.utils = utils.Utils()
|
|
|
|
def get_authentication_type(self, authentication_type):
|
|
authentication_type = authentication_type.lower()
|
|
|
|
open_types = ("none", "owe", "open")
|
|
for open_type in open_types:
|
|
if open_type in authentication_type:
|
|
return "open"
|
|
|
|
if "wep" in authentication_type or "shared" in authentication_type:
|
|
return "wep"
|
|
|
|
if "wpa" in authentication_type or "sae" in authentication_type:
|
|
return "wpa"
|
|
|
|
return None
|
|
|
|
def validate_wifi_password(self, authentication_type=None, password=None):
|
|
print("Validating password with authentication type: {}".format(authentication_type))
|
|
|
|
if password is None:
|
|
return None
|
|
|
|
if authentication_type is None:
|
|
return password
|
|
|
|
if authentication_type == "open":
|
|
return ""
|
|
|
|
try:
|
|
password.encode('ascii')
|
|
except UnicodeEncodeError:
|
|
return None
|
|
|
|
if 8 <= len(password) <= 63 and all(32 <= ord(c) <= 126 for c in password):
|
|
return password
|
|
|
|
return None
|
|
|
|
def get_wifi_password_macos(self, ssid):
|
|
output = self.run({
|
|
"args": ["security", "find-generic-password", "-wa", ssid]
|
|
})
|
|
|
|
if output[-1] != 0:
|
|
return None
|
|
|
|
try:
|
|
ssid_info = json.loads(output[0].strip())
|
|
password = ssid_info.get("password")
|
|
except:
|
|
password = output[0].strip() if output[0].strip() else None
|
|
|
|
return self.validate_wifi_password("wpa", password)
|
|
|
|
def get_wifi_password_windows(self, ssid):
|
|
output = self.run({
|
|
"args": ["netsh", "wlan", "show", "profile", ssid, "key=clear"]
|
|
})
|
|
|
|
if output[-1] != 0:
|
|
return None
|
|
|
|
authentication_type = None
|
|
password = None
|
|
|
|
for line in output[0].splitlines():
|
|
if authentication_type is None and "Authentication" in line:
|
|
authentication_type = self.get_authentication_type(line.split(":")[1].strip())
|
|
elif "Key Content" in line:
|
|
password = line.split(":")[1].strip()
|
|
|
|
return self.validate_wifi_password(authentication_type, password)
|
|
|
|
def get_wifi_password_linux(self, ssid):
|
|
output = self.run({
|
|
"args": ["nmcli", "--show-secrets", "connection", "show", ssid]
|
|
})
|
|
|
|
if output[-1] != 0:
|
|
return None
|
|
|
|
authentication_type = None
|
|
password = None
|
|
|
|
for line in output[0].splitlines():
|
|
if "802-11-wireless-security.key-mgmt:" in line:
|
|
authentication_type = self.get_authentication_type(line.split(":")[1].strip())
|
|
elif "802-11-wireless-security.psk:" in line:
|
|
password = line.split(":")[1].strip()
|
|
|
|
return self.validate_wifi_password(authentication_type, password)
|
|
|
|
def ask_network_count(self, total_networks):
|
|
self.utils.head("WiFi Network Retrieval")
|
|
print("")
|
|
print("Found {} WiFi networks on this device.".format(total_networks))
|
|
print("")
|
|
print("How many networks would you like to process?")
|
|
print(" 1-{} - Specific number (default: 5)".format(total_networks))
|
|
print(" A - All available networks")
|
|
print("")
|
|
|
|
num_choice = self.utils.request_input("Enter your choice: ").strip().lower() or "5"
|
|
|
|
if num_choice == "a":
|
|
print("Will process all available networks.")
|
|
return total_networks
|
|
|
|
try:
|
|
max_networks = min(int(num_choice), total_networks)
|
|
print("Will process up to {} networks.".format(max_networks))
|
|
return max_networks
|
|
except:
|
|
max_networks = min(5, total_networks)
|
|
print("Invalid choice. Will process up to {} networks.".format(max_networks))
|
|
return max_networks
|
|
|
|
def process_networks(self, ssid_list, max_networks, get_password_func):
|
|
networks = []
|
|
processed_count = 0
|
|
consecutive_failures = 0
|
|
max_consecutive_failures = 3
|
|
|
|
while len(networks) < max_networks and processed_count < len(ssid_list):
|
|
ssid = ssid_list[processed_count]
|
|
|
|
try:
|
|
print("")
|
|
print("Processing {}/{}: {}".format(processed_count + 1, len(ssid_list), ssid))
|
|
if os_name == "Darwin":
|
|
print("Please enter your administrator name and password or click 'Deny' to skip this network.")
|
|
|
|
password = get_password_func(ssid)
|
|
if password is not None:
|
|
if (ssid, password) not in networks:
|
|
consecutive_failures = 0
|
|
networks.append((ssid, password))
|
|
print("Successfully retrieved password.")
|
|
|
|
if len(networks) == max_networks:
|
|
break
|
|
else:
|
|
consecutive_failures += 1 if os_name == "Darwin" else 0
|
|
print("Could not retrieve password for this network.")
|
|
|
|
if consecutive_failures >= max_consecutive_failures:
|
|
continue_input = self.utils.request_input("\nUnable to retrieve passwords. Continue trying? (Yes/no): ").strip().lower() or "yes"
|
|
|
|
if continue_input != "yes":
|
|
break
|
|
|
|
consecutive_failures = 0
|
|
except Exception as e:
|
|
consecutive_failures += 1 if os_name == "Darwin" else 0
|
|
print("Error processing network '{}': {}".format(ssid, str(e)))
|
|
|
|
if consecutive_failures >= max_consecutive_failures:
|
|
continue_input = self.utils.request_input("\nUnable to retrieve passwords. Continue trying? (Yes/no): ").strip().lower() or "yes"
|
|
|
|
if continue_input != "yes":
|
|
break
|
|
|
|
consecutive_failures = 0
|
|
finally:
|
|
processed_count += 1
|
|
|
|
if processed_count >= max_networks and len(networks) < max_networks and processed_count < len(ssid_list):
|
|
continue_input = self.utils.request_input("\nOnly retrieved {}/{} networks. Try more to reach your target? (Yes/no): ".format(len(networks), max_networks)).strip().lower() or "yes"
|
|
|
|
if continue_input != "yes":
|
|
break
|
|
|
|
consecutive_failures = 0
|
|
|
|
return networks
|
|
|
|
def get_preferred_networks_macos(self, interface):
|
|
output = self.run({
|
|
"args": ["networksetup", "-listpreferredwirelessnetworks", interface]
|
|
})
|
|
|
|
if output[-1] != 0 or "Preferred networks on" not in output[0]:
|
|
return []
|
|
|
|
ssid_list = [network.strip() for network in output[0].splitlines()[1:] if network.strip()]
|
|
|
|
if not ssid_list:
|
|
return []
|
|
|
|
max_networks = self.ask_network_count(len(ssid_list))
|
|
|
|
self.utils.head("Administrator Authentication Required")
|
|
print("")
|
|
print("To retrieve WiFi passwords from the Keychain, macOS will prompt")
|
|
print("you for administrator credentials for each WiFi network.")
|
|
|
|
return self.process_networks(ssid_list, max_networks, self.get_wifi_password_macos)
|
|
|
|
def get_preferred_networks_windows(self):
|
|
output = self.run({
|
|
"args": ["netsh", "wlan", "show", "profiles"]
|
|
})
|
|
|
|
if output[-1] != 0:
|
|
return []
|
|
|
|
ssid_list = []
|
|
|
|
for line in output[0].splitlines():
|
|
if "All User Profile" in line:
|
|
try:
|
|
ssid = line.split(":")[1].strip()
|
|
if ssid:
|
|
ssid_list.append(ssid)
|
|
except:
|
|
continue
|
|
|
|
if not ssid_list:
|
|
return []
|
|
|
|
max_networks = len(ssid_list)
|
|
|
|
self.utils.head("WiFi Profile Extractor")
|
|
print("")
|
|
print("Retrieving passwords for {} network(s)...".format(len(ssid_list)))
|
|
|
|
return self.process_networks(ssid_list, max_networks, self.get_wifi_password_windows)
|
|
|
|
def get_preferred_networks_linux(self):
|
|
output = self.run({
|
|
"args": ["nmcli", "-t", "-f", "NAME", "connection", "show"]
|
|
})
|
|
|
|
if output[-1] != 0:
|
|
return []
|
|
|
|
ssid_list = [network.strip() for network in output[0].splitlines() if network.strip()]
|
|
|
|
if not ssid_list:
|
|
return []
|
|
|
|
max_networks = len(ssid_list)
|
|
|
|
self.utils.head("WiFi Profile Extractor")
|
|
print("")
|
|
print("Retrieving passwords for {} network(s)...".format(len(ssid_list)))
|
|
|
|
return self.process_networks(ssid_list, max_networks, self.get_wifi_password_linux)
|
|
|
|
def get_wifi_interfaces(self):
|
|
output = self.run({
|
|
"args": ["networksetup", "-listallhardwareports"]
|
|
})
|
|
|
|
if output[-1] != 0:
|
|
return []
|
|
|
|
interfaces = []
|
|
|
|
for interface_info in output[0].split("\n\n"):
|
|
if "Device: en" in interface_info:
|
|
try:
|
|
interface = "en{}".format(int(interface_info.split("Device: en")[1].split("\n")[0]))
|
|
|
|
test_output = self.run({
|
|
"args": ["networksetup", "-listpreferredwirelessnetworks", interface]
|
|
})
|
|
|
|
if test_output[-1] == 0 and "Preferred networks on" in test_output[0]:
|
|
interfaces.append(interface)
|
|
except:
|
|
continue
|
|
|
|
return interfaces
|
|
|
|
def get_profiles(self):
|
|
os_name = platform.system()
|
|
|
|
self.utils.head("WiFi Profile Extractor")
|
|
print("")
|
|
print("\033[1;93mNote:\033[0m")
|
|
print("- When using itlwm kext, WiFi appears as Ethernet in macOS")
|
|
print("- You'll need Heliport app to manage WiFi connections in macOS")
|
|
print("- This step will enable auto WiFi connections at boot time")
|
|
print(" and is useful for users installing macOS via Recovery OS")
|
|
print("")
|
|
|
|
while True:
|
|
user_input = self.utils.request_input("Would you like to scan for WiFi profiles? (Yes/no): ").strip().lower()
|
|
|
|
if user_input == "yes":
|
|
break
|
|
elif user_input == "no":
|
|
return []
|
|
else:
|
|
print("\033[91mInvalid selection, please try again.\033[0m\n\n")
|
|
|
|
profiles = []
|
|
self.utils.head("Detecting WiFi Profiles")
|
|
print("")
|
|
print("Scanning for WiFi profiles...")
|
|
|
|
if os_name == "Windows":
|
|
profiles = self.get_preferred_networks_windows()
|
|
elif os_name == "Linux":
|
|
profiles = self.get_preferred_networks_linux()
|
|
elif os_name == "Darwin":
|
|
wifi_interfaces = self.get_wifi_interfaces()
|
|
|
|
if wifi_interfaces:
|
|
for interface in wifi_interfaces:
|
|
print("Checking interface: {}".format(interface))
|
|
interface_profiles = self.get_preferred_networks_macos(interface)
|
|
if interface_profiles:
|
|
profiles = interface_profiles
|
|
break
|
|
else:
|
|
print("No WiFi interfaces detected.")
|
|
|
|
if not profiles:
|
|
self.utils.head("WiFi Profile Extractor")
|
|
print("")
|
|
print("No WiFi profiles with saved passwords were found.")
|
|
self.utils.request_input()
|
|
|
|
self.utils.head("WiFi Profile Extractor")
|
|
print("")
|
|
print("Found the following WiFi profiles with saved passwords:")
|
|
print("")
|
|
print("Index SSID Password")
|
|
print("-------------------------------------------------------")
|
|
for index, (ssid, password) in enumerate(profiles, start=1):
|
|
print("{:<6} {:<32} {:<8}".format(index, ssid[:31] + "..." if len(ssid) > 31 else ssid, password[:12] + "..." if len(password) > 12 else password))
|
|
print("")
|
|
print("Successfully applied {} WiFi profiles.".format(len(profiles)))
|
|
print("")
|
|
|
|
self.utils.request_input()
|
|
return profiles |