mirror of
https://github.com/AlienMajik/pwnagotchi_plugins.git
synced 2025-07-01 18:37:27 -04:00

Realistic MAC Address Generation Improvement: The updated version uses a more realistic MAC address by incorporating an OUI (Organizationally Unique Identifier) and randomizing the last three bytes within a restricted range. Flexible Randomization Interval Improvement: The randomization interval is now flexible, varying between 30 minutes and 2 hours. Randomizing the interval adds unpredictability, making the MAC address changes harder to detect. This increases stealth. Improved MAC Randomization for Monitor Mode Improvement: When the Wi-Fi interface is in monitor mode, the plugin temporarily switches to managed mode to change the MAC address and restores monitor mode afterward. Updated UI Handling Improvement: The UI is now updated more effectively by directly modifying the value attribute of the UI components in on_ui_update(). Better Error Handling and Logging Improvement: The plugin now has enhanced error handling for subprocess calls, such as bringing the interface down or changing the MAC address. More detailed logs are provided for different stages. Initial MAC Address Randomization Improvement: The plugin now performs an initial MAC address randomization when it is loaded (self.randomize_mac() in on_loaded()). This ensures that the device's MAC address is randomized as soon as the plugin starts, providing enhanced privacy from the start. Time-Dependent MAC Randomization Improvement: The next MAC address change time is now dynamically calculated based on the random interval. This ensures the MAC address change schedule follows the random interval, making it harder to predict.
177 lines
7.2 KiB
Python
177 lines
7.2 KiB
Python
import logging
|
|
import subprocess
|
|
import time
|
|
import random
|
|
|
|
import pwnagotchi.plugins as plugins
|
|
from pwnagotchi.ui.components import LabeledValue
|
|
from pwnagotchi.ui.view import BLACK
|
|
import pwnagotchi.ui.fonts as fonts
|
|
|
|
class Neurolyzer(plugins.Plugin):
|
|
__author__ = 'AlienMajik'
|
|
__version__ = '1.5.1'
|
|
__license__ = 'GPL3'
|
|
__description__ = "A plugin for enhanced stealth and privacy using realistic OUIs."
|
|
|
|
def __init__(self):
|
|
self.enabled = False
|
|
self.wifi_interface = 'wlan0'
|
|
self.operation_mode = 'stealth' # 'normal' or 'stealth'
|
|
self.mac_change_interval = 3600 # Interval in seconds
|
|
self.last_mac_change_time = time.time()
|
|
self.next_mac_change_time = self.last_mac_change_time + self.mac_change_interval
|
|
self.last_random_mac = None
|
|
|
|
# UI custom positions
|
|
self.mode_label_position = (0, 0)
|
|
self.next_mac_change_label_position = (0, 0)
|
|
|
|
def on_loaded(self):
|
|
self.enabled = self.options.get('enabled', False)
|
|
self.wifi_interface = self.options.get('wifi_interface', 'wlan0')
|
|
self.operation_mode = self.options.get('operation_mode', 'stealth')
|
|
self.mac_change_interval = self.options.get('mac_change_interval', 3600)
|
|
self.next_mac_change_time = time.time() + self.mac_change_interval
|
|
|
|
# UI positions from config
|
|
self.mode_label_position = (
|
|
self.options.get('mode_label_x', 0),
|
|
self.options.get('mode_label_y', 0)
|
|
)
|
|
self.next_mac_change_label_position = (
|
|
self.options.get('next_mac_change_label_x', 0),
|
|
self.options.get('next_mac_change_label_y', 10)
|
|
)
|
|
|
|
if self.enabled:
|
|
logging.info("[Neurolyzer] Plugin loaded. Operating in %s mode." % self.operation_mode)
|
|
self.randomize_mac() # Initial MAC address randomization
|
|
else:
|
|
logging.info("[Neurolyzer] Plugin not enabled.")
|
|
|
|
def on_ui_setup(self, ui):
|
|
if not self.enabled:
|
|
return
|
|
|
|
self.mode_label = LabeledValue(
|
|
color=BLACK,
|
|
label="Mode:",
|
|
value=self.operation_mode.capitalize(),
|
|
position=self.mode_label_position,
|
|
label_font=fonts.Small,
|
|
text_font=fonts.Small
|
|
)
|
|
ui.add_element('neurolyzer_mode', self.mode_label)
|
|
|
|
self.next_mac_change_label = LabeledValue(
|
|
color=BLACK,
|
|
label="Next MAC change:",
|
|
value="Calculating...",
|
|
position=self.next_mac_change_label_position,
|
|
label_font=fonts.Small,
|
|
text_font=fonts.Small
|
|
)
|
|
ui.add_element('neurolyzer_next_mac', self.next_mac_change_label)
|
|
|
|
def on_ui_update(self, ui):
|
|
if not self.enabled:
|
|
return
|
|
|
|
remaining_time = self.next_mac_change_time - time.time()
|
|
if remaining_time <= 0:
|
|
self.randomize_mac()
|
|
self.next_mac_change_time = time.time() + self.randomize_interval()
|
|
|
|
# Update UI labels by directly setting the value attribute.
|
|
self.next_mac_change_label.value = "%dm" % (remaining_time // 60)
|
|
self.mode_label.value = self.operation_mode.capitalize()
|
|
|
|
def randomize_mac(self):
|
|
if self.operation_mode != 'stealth' or not self.enabled:
|
|
return
|
|
|
|
new_mac = self.generate_realistic_mac()
|
|
|
|
if 'mon' in self.wifi_interface.lower():
|
|
# For monitor mode interfaces, switch temporarily to managed mode.
|
|
try:
|
|
subprocess.run(['sudo', 'ip', 'link', 'set', 'dev', self.wifi_interface, 'down'],
|
|
check=True, stderr=subprocess.DEVNULL)
|
|
except subprocess.CalledProcessError as e:
|
|
logging.warning(f"[Neurolyzer] Failed to bring down interface {self.wifi_interface}: {e}")
|
|
|
|
try:
|
|
subprocess.run(['sudo', 'iwconfig', self.wifi_interface, 'mode', 'managed'],
|
|
check=True, stderr=subprocess.DEVNULL)
|
|
except subprocess.CalledProcessError as e:
|
|
logging.error(f"[Neurolyzer] Failed to set {self.wifi_interface} to managed mode: {e}")
|
|
return
|
|
|
|
try:
|
|
subprocess.run(['sudo', 'ip', 'link', 'set', 'dev', self.wifi_interface, 'address', new_mac],
|
|
check=True, stderr=subprocess.DEVNULL)
|
|
except subprocess.CalledProcessError as e:
|
|
logging.error(f"[Neurolyzer] MAC address change failed: {e}")
|
|
return
|
|
|
|
try:
|
|
subprocess.run(['sudo', 'ip', 'link', 'set', 'dev', self.wifi_interface, 'up'],
|
|
check=True, stderr=subprocess.DEVNULL)
|
|
except subprocess.CalledProcessError as e:
|
|
logging.error(f"[Neurolyzer] Failed to bring up interface {self.wifi_interface}: {e}")
|
|
return
|
|
|
|
# Optionally, switch back to monitor mode if needed:
|
|
# try:
|
|
# subprocess.run(['iwconfig', self.wifi_interface, 'mode', 'monitor'],
|
|
# check=True, stderr=subprocess.DEVNULL)
|
|
# except subprocess.CalledProcessError as e:
|
|
# logging.warning(f"[Neurolyzer] Failed to set {self.wifi_interface} back to monitor mode: {e}")
|
|
else:
|
|
# For non-monitor mode interfaces, use the standard sequence.
|
|
try:
|
|
subprocess.run(['sudo', 'ip', 'link', 'set', 'dev', self.wifi_interface, 'down'],
|
|
check=True, stderr=subprocess.DEVNULL)
|
|
except subprocess.CalledProcessError as e:
|
|
logging.warning(f"[Neurolyzer] Failed to bring down interface {self.wifi_interface}: {e}")
|
|
|
|
try:
|
|
subprocess.run(['sudo', 'ip', 'link', 'set', 'dev', self.wifi_interface, 'address', new_mac],
|
|
check=True, stderr=subprocess.DEVNULL)
|
|
except subprocess.CalledProcessError as e:
|
|
logging.error(f"[Neurolyzer] MAC address change failed: {e}")
|
|
return
|
|
|
|
try:
|
|
subprocess.run(['sudo', 'ip', 'link', 'set', 'dev', self.wifi_interface, 'up'],
|
|
check=True, stderr=subprocess.DEVNULL)
|
|
except subprocess.CalledProcessError as e:
|
|
logging.error(f"[Neurolyzer] Failed to bring up interface {self.wifi_interface}: {e}")
|
|
return
|
|
|
|
self.last_mac_change_time = time.time()
|
|
self.last_random_mac = new_mac
|
|
logging.info(f"[Neurolyzer] MAC address changed to {new_mac} for {self.wifi_interface}.")
|
|
|
|
def generate_realistic_mac(self):
|
|
"""Generate a stealthy MAC address with a less identifiable OUI."""
|
|
mac = [
|
|
0x00, 0x25, 0x96,
|
|
random.randint(0x00, 0x7F),
|
|
random.randint(0x00, 0x7F),
|
|
random.randint(0x00, 0x7F)
|
|
]
|
|
mac_address = ':'.join(f"{byte:02x}" for byte in mac)
|
|
return mac_address
|
|
|
|
def randomize_interval(self):
|
|
"""Return a random interval between 30 minutes and 2 hours."""
|
|
return random.randint(1800, 7200)
|
|
|
|
def on_unload(self):
|
|
if not self.enabled:
|
|
return
|
|
logging.info("[Neurolyzer] Plugin unloaded.")
|
|
|