From 7a2704284acc08af8aef97d911412f1aa122e401 Mon Sep 17 00:00:00 2001 From: D4MI4NX <105593627+D4MI4NX@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:49:32 +0200 Subject: [PATCH] Made all strings use the AnsiColorCode class color variables --- BlueDucky.py | 70 ++++++++++++--------------------------- utils/color.py | 10 ++++++ utils/menu_functions.py | 72 +++++++++++++++-------------------------- 3 files changed, 57 insertions(+), 95 deletions(-) create mode 100644 utils/color.py diff --git a/BlueDucky.py b/BlueDucky.py index 1575e3b..7705ead 100644 --- a/BlueDucky.py +++ b/BlueDucky.py @@ -5,38 +5,31 @@ from enum import Enum import subprocess import os + +from utils.color import color from utils.menu_functions import (main_menu, read_duckyscript, run, restart_bluetooth_daemon, get_target_address) from utils.register_device import register_hid_profile, agent_loop child_processes = [] -# ANSI escape sequences for colors -class AnsiColorCode: - RED = '\033[91m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - BLUE = '\033[94m' - WHITE = '\033[97m' - RESET = '\033[0m' - # Custom log level NOTICE_LEVEL = 25 # Custom formatter class with added color for NOTICE class ColorLogFormatter(logging.Formatter): COLOR_MAP = { - logging.DEBUG: AnsiColorCode.BLUE, - logging.INFO: AnsiColorCode.GREEN, - logging.WARNING: AnsiColorCode.YELLOW, - logging.ERROR: AnsiColorCode.RED, - logging.CRITICAL: AnsiColorCode.RED, - NOTICE_LEVEL: AnsiColorCode.BLUE, # Color for NOTICE level + logging.DEBUG: color.BLUE, + logging.INFO: color.GREEN, + logging.WARNING: color.YELLOW, + logging.ERROR: color.RED, + logging.CRITICAL: color.RED, + NOTICE_LEVEL: color.BLUE, # Color for NOTICE level } def format(self, record): - color = self.COLOR_MAP.get(record.levelno, AnsiColorCode.WHITE) + fmt_color = self.COLOR_MAP.get(record.levelno, color.WHITE) message = super().format(record) - return f'{color}{message}{AnsiColorCode.RESET}' + return f'{fmt_color}{message}{color.RESET}' # Method to add to the Logger class @@ -267,17 +260,12 @@ 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(f"{reset}[{red}!{reset}] {red}CRITICAL ERROR{reset}: {reset}Attempted Connection to {red}{target_address} {reset}was {red}denied{reset}.") + print(f"{color.RESET}[{color.RED}!{color.RESET}] {color.RED}CRITICAL ERROR{color.RESET}: {color.RESET}Attempted Connection to {color.RED}{target_address} {color.RESET}was {color.RED}denied{color.RESET}.") return self.connected @@ -640,37 +628,29 @@ def setup_and_connect(connection_manager, target_address, adapter_id): 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(f"{reset}[{red}!{reset}] {red}CRITICAL{reset}: {blue}bluetoothctl {reset}is not installed or not working properly.") + print(f"{color.RESET}[{color.RED}!{color.RESET}] {color.RED}CRITICAL{color.RESET}: {color.BLUE}bluetoothctl {color.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(f"{reset}[{red}!{reset}] {red}CRITICAL{reset}: No {blue}Bluetooth adapters{reset} have been detected.") + print(f"{color.RESET}[{color.RED}!{color.RESET}] {color.RED}CRITICAL{color.RESET}: No {color.BLUE}Bluetooth adapters{color.RESET} have been detected.") return False - yellow = "\033[93m" - # 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(f"{reset}[{red}!{reset}] {yellow}WARNING{reset}: Your {blue}Bluetooth devices{reset} might not be supported.") + print(f"{color.RESET}[{color.RED}!{color.RESET}] {color.YELLOW}WARNING{color.RESET}: Your {color.BLUE}Bluetooth devices{color.RESET} might not be supported.") time.sleep(2) 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() @@ -686,17 +666,11 @@ def main(): payload_folder = os.path.join(script_directory, 'payloads/') # Specify the relative path to the payloads folder. payloads = os.listdir(payload_folder) - blue = "\033[0m" - red = "\033[91m" - reset = "\033[0m" - print(f"\nAvailable payloads{blue}:") + print(f"\nAvailable payloads{color.BLUE}:") for idx, payload_file in enumerate(payloads, 1): # Check and enumerate the files inside the payload folder. - print(f"{reset}[{blue}{idx}{reset}]{blue}: {blue}{payload_file}") + print(f"{color.RESET}[{color.BLUE}{idx}{color.RESET}]{color.BLUE}: {color.BLUE}{payload_file}") - 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{reset}: {blue}") + payload_choice = input(f"\n{color.BLUE}Enter the number that represents the payload you would like to load{color.RESET}: {color.BLUE}") selected_payload = None try: @@ -706,10 +680,10 @@ def main(): print(f"Invalid payload choice. No payload selected.") if selected_payload is not None: - print(f"{blue}Selected payload{reset}: {blue}{selected_payload}") + print(f"{color.BLUE}Selected payload{color.RESET}: {color.BLUE}{selected_payload}") duckyscript = read_duckyscript(selected_payload) else: - print(f"{red}No payload selected.") + print(f"{color.RED}No payload selected.") @@ -732,7 +706,7 @@ def main(): break # Exit loop if successful except ReconnectionRequiredException as e: - log.info(f"{reset}Reconnection required. Attempting to reconnect{blue}...") + log.info(f"{color.RESET}Reconnection required. Attempting to reconnect{color.BLUE}...") current_line = e.current_line current_position = e.current_position connection_manager.close_all() @@ -741,12 +715,10 @@ def main(): 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}") + print(f"{color.BLUE}Successfully Removed device{color.RESET}: {color.BLUE}{target_address}{color.RESET}") if __name__ == "__main__": setup_logging() diff --git a/utils/color.py b/utils/color.py new file mode 100644 index 0000000..c10853a --- /dev/null +++ b/utils/color.py @@ -0,0 +1,10 @@ +# ANSI escape sequences for colors +class AnsiColorCode: + RED = '\033[91m' + GREEN = '\033[92m' + YELLOW = '\033[93m' + BLUE = '\033[94m' + WHITE = '\033[97m' + RESET = '\033[0m' + +color = AnsiColorCode() \ No newline at end of file diff --git a/utils/menu_functions.py b/utils/menu_functions.py index 637a171..f0607c7 100644 --- a/utils/menu_functions.py +++ b/utils/menu_functions.py @@ -1,15 +1,15 @@ import os, bluetooth, re, subprocess, time, curses import logging as log +from utils.color import color + ########################## # UI Redesign by Lamento # ########################## def get_target_address(): - blue = "\033[94m" - reset = "\033[0m" - print(f"\n What is the target address{blue}? {reset}Leave blank and we will scan for you{blue}!{reset}") - target_address = input(f"\n {blue}> ") + print(f"\n What is the target address{color.BLUE}? {color.RESET}Leave blank and we will scan for you{color.BLUE}!{color.RESET}") + target_address = input(f"\n {color.BLUE}> ") if target_address == "": devices = scan_for_devices() @@ -18,7 +18,7 @@ def get_target_address(): if len(devices) == 1 and isinstance(devices[0], tuple) and len(devices[0]) == 2: # A single known device was chosen, no need to ask for selection # I think it would be better to ask, as sometimes I do not want to chose this device and actually need solely to scan for actual devices. - confirm = input(f"\n Would you like to register this device{blue}:\n{reset}{devices[0][1]} {devices[0][0]}{blue}? {blue}({reset}y{blue}/{reset}n{blue}) {blue}").strip().lower() + confirm = input(f"\n Would you like to register this device{color.BLUE}:\n{color.RESET}{devices[0][1]} {devices[0][0]}{color.BLUE}? {color.BLUE}({color.RESET}y{color.BLUE}/{color.RESET}n{color.BLUE}) {color.BLUE}").strip().lower() if confirm == 'y' or confirm == 'yes': return devices[0][0] elif confirm != 'y' or 'yes': @@ -26,8 +26,8 @@ def get_target_address(): else: # Show list of scanned devices for user selection for idx, (addr, name) in enumerate(devices): - print(f"{reset}[{blue}{idx + 1}{reset}] {blue}Device Name{reset}: {blue}{name}, {blue}Address{reset}: {blue}{addr}") - selection = int(input(f"\n{reset}Select a device by number{blue}: {blue}")) - 1 + print(f"{color.RESET}[{color.BLUE}{idx + 1}{color.RESET}] {color.BLUE}Device Name{color.RESET}: {color.BLUE}{name}, {color.BLUE}Address{color.RESET}: {color.BLUE}{addr}") + selection = int(input(f"\n{color.RESET}Select a device by number{color.BLUE}: {color.BLUE}")) - 1 if 0 <= selection < len(devices): target_address = devices[selection][0] else: @@ -92,40 +92,24 @@ def save_devices_to_file(devices, filename='known_devices.txt'): def scan_for_devices(): main_menu() - blue = "\033[94m" - error = "\033[91m" - reset = "\033[0m" - # Load known devices known_devices = load_known_devices() if known_devices: - blue = "\033[94m" - error = "\033[91m" - reset = "\033[0m" - print(f"\n{reset}Known devices{blue}:") + print(f"\n{color.RESET}Known devices{color.BLUE}:") for idx, (addr, name) in enumerate(known_devices): - blue = "\033[94m" - error = "\033[91m" - reset = "\033[0m" - print(f"{blue}{idx + 1}{reset}: Device Name: {blue}{name}, Address: {blue}{addr}") + print(f"{color.BLUE}{idx + 1}{color.RESET}: Device Name: {color.BLUE}{name}, Address: {color.BLUE}{addr}") - blue = "\033[94m" - error = "\033[91m" - reset = "\033[0m" - use_known_device = input(f"\n{reset}Do you want to use one of these known devices{blue}? {blue}({reset}yes{blue}/{reset}no{blue}): ") + use_known_device = input(f"\n{color.RESET}Do you want to use one of these known devices{color.BLUE}? {color.BLUE}({color.RESET}yes{color.BLUE}/{color.RESET}no{color.BLUE}): ") if use_known_device.lower() == 'yes': - device_choice = int(input(f"{reset}Enter the index number of the device to attack{blue}: ")) + device_choice = int(input(f"{color.RESET}Enter the index number of the device to attack{color.BLUE}: ")) return [known_devices[device_choice - 1]] # Normal Bluetooth scan - blue = "\033[94m" - error = "\033[91m" - reset = "\033[0m" - print(f"\n{reset}Attempting to scan now{blue}...") + print(f"\n{color.RESET}Attempting to scan now{color.BLUE}...") nearby_devices = bluetooth.discover_devices(duration=8, lookup_names=True, flush_cache=True, lookup_class=True) device_list = [] if len(nearby_devices) == 0: - print(f"\n{reset}[{error}+{reset}] No nearby devices found.") + print(f"\n{color.RESET}[{error}+{color.RESET}] No nearby devices found.") else: print("\nFound {} nearby device(s):".format(len(nearby_devices))) for idx, (addr, name, _) in enumerate(nearby_devices): @@ -137,7 +121,7 @@ def scan_for_devices(): known_devices += new_devices save_devices_to_file(known_devices) for idx, (addr, name) in enumerate(new_devices): - print(f"{reset}{idx + 1}{blue}: {blue}Device Name{reset}: {blue}{name}{reset}, {blue}Address{reset}: {blue}{addr}") + print(f"{color.RESET}{idx + 1}{color.BLUE}: {color.BLUE}Device Name{color.RESET}: {color.BLUE}{name}{color.RESET}, {color.BLUE}Address{color.RESET}: {color.BLUE}{addr}") return device_list def getterm(): @@ -146,8 +130,6 @@ def getterm(): def print_menu(): - blue = '\033[94m' - reset = "\033[0m" title = "BlueDucky - Bluetooth Device Attacker" vertext = "Ver 2.1" motd1 = f"Remember, you can still attack devices without visibility.." @@ -155,13 +137,13 @@ def print_menu(): terminal_width = getterm() separator = "=" * terminal_width - print(blue + separator) # Blue color for separator - print(reset + title.center(len(separator))) # Centered Title in blue - print(blue + vertext.center(len(separator))) # Centered Version - print(blue + separator + reset) # Blue color for separator + print(color.BLUE + separator) # Blue color for separator + print(color.RESET + title.center(len(separator))) # Centered Title in blue + print(color.BLUE + vertext.center(len(separator))) # Centered Version + print(color.BLUE + separator + color.RESET) # Blue color for separator print(motd1.center(len(separator)))# used the same method for centering print(motd2.center(len(separator)))# used the same method for centering - print(blue + separator + reset) # Blue color for separator + print(color.BLUE + separator + color.RESET) # Blue color for separator def main_menu(): clear_screen() @@ -196,13 +178,11 @@ title = "BlueDucky - Bluetooth Device Attacker" vertext = "Ver 2.1" terminal_width = getterm() separator = "=" * terminal_width -blue = "\033[0m" -reset = "\033[0m" -print(blue + separator) # Blue color for separator -print(reset + title.center(len(separator))) # White color for title -print(blue + vertext.center(len(separator))) # White blue for version number -print(blue + separator + reset) # Blue color for separator -print(f"{reset}Remember, you can still attack devices without visibility{blue}.." + reset) -print(f"{blue}If you have their {reset}MAC address{blue}.." + reset) -print(blue + separator + reset) # Blue color for separator +print(color.BLUE + separator) # Blue color for separator +print(color.RESET + title.center(len(separator))) # White color for title +print(color.BLUE + vertext.center(len(separator))) # White blue for version number +print(color.BLUE + separator + color.RESET) # Blue color for separator +print(f"{color.RESET}Remember, you can still attack devices without visibility{color.BLUE}.." + color.RESET) +print(f"{color.BLUE}If you have their {color.RESET}MAC address{color.BLUE}.." + color.RESET) +print(color.BLUE + separator + color.RESET) # Blue color for separator