diff --git a/BlueDucky.py b/BlueDucky.py index f5b0465..b4d2b72 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{reset}: {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() diff --git a/README.md b/README.md index cd58479..5097547 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ -# BlueDucky (Android) 🦆 +# BlueDucky Ver 2.1 (Android) 🦆 Thanks to all the people at HackNexus. Make sure you come join us on VC ! https://discord.gg/HackNexus 1. [saad0x1's GitHub](https://github.com/saad0x1) 2. [spicydll's GitHub](https://github.com/spicydll) +3. [lamentomori's GitHub](https://github.com/lamentomori)

@@ -75,6 +76,15 @@ python3 BlueDucky.py 🚧 Work in Progress: - Suggest me ideas +## Version 2.1 🐛 +- Updated UI +- Improved User Experience +- Bluetooth Debugger; Checks your bluetooth adapters, and installed dependancies before allowing access to the application, this is to prevent devices that are not supported. +- Please Note: Numerous Changes have been made,please reference the commit history for specific changes. + +## What's Planned for the Next Release? +- Integrated DuckyScript Console for attacks that want to maintain persistance, after a payload has been ran +- Suggest What Should be added next! Join https://discord.gg/HackNexus #### 📝 Example payload.txt: ```bash diff --git a/images/duckmenu.png b/images/duckmenu.png index e28ca18..703c31e 100644 Binary files a/images/duckmenu.png and b/images/duckmenu.png differ diff --git a/utils/menu_functions.py b/utils/menu_functions.py index 2affe1b..637a171 100644 --- a/utils/menu_functions.py +++ b/utils/menu_functions.py @@ -1,7 +1,15 @@ -import os, bluetooth,re, subprocess, time, curses +import os, bluetooth, re, subprocess, time, curses import logging as log + +########################## +# UI Redesign by Lamento # +########################## + def get_target_address(): - target_address = input("\nWhat is the target address? Leave blank and we will scan for you: ") + 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}> ") if target_address == "": devices = scan_for_devices() @@ -10,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"Would you like to enter this device :\n{devices[0][1]} {devices[0][0]} ? (y/n)\n").strip().lower() + 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() if confirm == 'y' or confirm == 'yes': return devices[0][0] elif confirm != 'y' or 'yes': @@ -18,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"{idx + 1}: Device Name: {name}, Address: {addr}") - selection = int(input("\nSelect a device by number: ")) - 1 + 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 if 0 <= selection < len(devices): target_address = devices[selection][0] else: @@ -46,38 +54,30 @@ def run(command): def print_fancy_ascii_art(): ascii_art = """ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣄⣤⣤⣄⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⡶⠟⠛⠉⠉⠉⠉⠉⠉⠉⠉⠉⠙⠛⠷⢶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⢷⣤⡀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣆⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣧⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣠⣤⣤⣤⣤⣤⣄⣀⡀⠀⠀⢹⣧⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣶⣶⣿⣷⣶⠶⠛⠛⠛⠛⠳⢶⣦⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣯⠉⠉⠉⠉⠉⠛⣷⠀⠀⢿⡄⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⢀⣠⣿⣀⡀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⠀⢀⣀⣀⣤⣴⠟⠀⠀⠸⣧⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⣙⣿⣿⣿⣿⣿⣿⠶⠶⠶⠿⠛⠛⠛⠛⠛⠛⢷⣦⡀⠉⠙⠛⠛⠛⠛⠛⠛⠛⠋⠉⠁⠀⠀⠀⠀⠀⣿⠀⠀⠀ -⠀⢀⣠⣴⠶⠾⠛⠛⠛⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡀⠀⠀ -⢠⣿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢗⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀ -⠈⢿⣦⣄⣀⣀⠀⠀⢀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣤⣤⣤⣄⣀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀ -⠀⠀⠈⠉⠛⠛⠛⢻⣟⠛⠛⠛⠛⠛⠋⠉⠉⠉⠉⠉⠉⠉⠉⠉⠻⠷⠀⢀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠛⠷⢶⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣴⠶⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⢹⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⡇⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣇⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣆⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⢶ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⡾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣴⠟⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⢀⣤⣤⡀⢀⣤⣤⡀⠀⣤⠀⠀⢀⣤⣄⢀⣤⣤⡀⠀⠀⣤⠀⠀⣠⠀⢀⣄⠀⠀⣠⣤⡀⠀⠀⠀⡀⠀⣠⡀⣠⣤⣤⣠⡀⠀⣤⢀⣤⣤⡀⣤⣤⡀ -⢸⣯⣹⡗⣿⣿⡏⠀⣼⣿⣇⢰⡿⠉⠃⣿⣿⡍⠀⠀⠀⢿⣤⣦⣿⠀⣾⢿⡆⢾⣯⣝⡃⠀⠀⢰⣿⣆⣿⡧⣿⣽⡍⠘⣷⣸⡏⣾⣿⡯⢸⣯⣩⡿ -⢸⡟⠉⠀⢿⣶⣶⢰⡿⠟⢻⡾⢷⣴⡆⢿⣶⣶⠄⠀⠀⠸⡿⠻⡿⣼⡿⠟⢿⢤⣭⣿⠟⠀⠀⢸⡇⠻⣿⠃⣿⣼⣶⠀⢻⡟⠀⢿⣧⣶⠸⣿⠻⣧ -⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⢀⡀⠀⠀⠀⠀⣀⠀⠀⠀⠀⣀⡀⠈⢀⣀⣀⠀⣁⣀⣀⢀⡀⠀⢀⣀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⠀⢠⣧⡀⣿⠀⠀⠀⣼⡿⢿⣄⣼⡟⢿⡿⠿⣿⠿⢻⣧⢠⡿⠿⣧⣀⣿⡄⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣧⣾⡟⣷⣿⠀⠀⠘⣿⣀⣸⡟⢹⡿⠟⠁⠀⣿⡀⢸⣏⢿⣇⣠⣿⢻⣏⢿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⠁⠀⠙⠙⠁⠘⠋⠀⠀⠀⠈⠉⠉⠀⠘⠁⠀⠀⠀⠉⠁⠈⠁⠀⠉⠉⠁⠈⠋⠈⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀""" + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠄⠒⠒⠒⠒⠒⠒⠂⠠⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠴⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠓⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠞⠁⠀⠀⠀⠀⣀⡤⠴⠒⠒⠒⠒⠦⠤⣀⠀⠀⠀⠙⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⢰⠋⠀⠀⠀⣠⠖⠋⢀⣄⣀⡀⠀⠀⠀⠀⠀⠀⠉⠲⣄⠀⠈⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⢠⠇⠀⠀⢀⡼⠁⠀⣴⣿⡛⠻⣿⣧⡀⠀⠀⠀⠀⠀⠀⠈⠳⡄⡿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⣼⣀⣀⣀⡜⠀⠀⠀⣿⣿⣿⣿⣿⣿⡧⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⣀⡤⠟⠁⠀⠈⠙⡶⣄⡀⠈⠻⢿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠇⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⣤⣤⠖⠖⠛⠉⠈⣀⣀⠀⠴⠊⠀⠀⣹⣷⣶⡏⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⣀⡀⠀⠀ + ⠘⠿⣿⣷⣶⣶⣶⣶⣤⣶⣶⣶⣿⣿⣿⡿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡜⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⠤⠖⠒⠋⠉⠁⠙⣆⠀ + ⠀⠀⠀⠀⠉⠉⠉⠉⠙⠿⣍⣩⠟⠋⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣾⣖⣶⣶⢾⠯⠽⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡄ + ⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⠚⠁⠀⠀⠀⠀⠈⠓⠤⠀⠀⠀⠀⠀⠀⠐⠒⠚⠉⠉⠁⠀⠀⠀⠀⠀⠀⢀⣀⣀⠀⣀⢀⠀⠀⠀⠀⠀⠀⠀⣇ + ⠀⠀⠀⠀⠀⠀⠀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⠤⠤⠖⠒⠚⠉⠉⠁⠀⠀⠀⢸⢸⣦⠀⠀⠀⠀⠀⠀⢸ + ⠀⠀⠀⠀⠀⢠⠎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⡠⠤⠴⠒⠒⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡏⣸⡏⠇⠀⠀⠀⠀⠀⢸ + ⠀⠀⠀⠀⢠⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠞⢠⡿⠀⠀⠀⠀⠀⠀⠀⢸ + ⠀⠀⠀⠀⣾⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠊⣠⡟⠀⠀⠀⠀⠀⠀⠀⠀⡏ + ⠀⠀⠀⠀⡏⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠖⠉⢀⣴⠏⠠⠀⠀⠀⠀⠀⠀⠀⣸⠁ + ⠀⠀⠀⠀⢹⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠒⠒⠢⠤⠄⠀⠀⠀⠀⠀⠈⠁⠀⣠⣶⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⢠⠃⠀ + ⠀⠀⠀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣴⠿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠃⠀⠀ + ⠀⠀⠀⠀⠀⠈⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⡶⠿⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠃⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠳⣄⢀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠤⠖⣪⡵⠋⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠈⠑⠫⠭⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣭⣭⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⡴⠶⠛⠉⠀⠀⠀⠀⠀⠀⠀ +""" - print("\033[1;36m" + ascii_art + "\033[0m") # Cyan color + print("\033[94m" + ascii_art + "\033[0m") # Blue color def clear_screen(): os.system('clear') @@ -88,45 +88,44 @@ def save_devices_to_file(devices, filename='known_devices.txt'): for addr, name in devices: file.write(f"{addr},{name}\n") -def get_yes_no(): - stdscr = curses.initscr() - curses.cbreak() - stdscr.keypad(1) - - while True: - key = stdscr.getch() - if key == ord('y'): - response = 'yes' - break - elif key == ord('n'): - response = 'no' - break - - curses.endwin() - return response - # Function to scan for devices 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: - print("\nKnown devices:") + blue = "\033[94m" + error = "\033[91m" + reset = "\033[0m" + print(f"\n{reset}Known devices{blue}:") for idx, (addr, name) in enumerate(known_devices): - print(f"{idx + 1}: Device Name: {name}, Address: {addr}") + blue = "\033[94m" + error = "\033[91m" + reset = "\033[0m" + print(f"{blue}{idx + 1}{reset}: Device Name: {blue}{name}, Address: {blue}{addr}") - use_known_device = input("\nDo you want to use one of these known devices? (yes/no): ") + 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}): ") if use_known_device.lower() == 'yes': - device_choice = int(input("Enter the number of the device: ")) + device_choice = int(input(f"{reset}Enter the index number of the device to attack{blue}: ")) return [known_devices[device_choice - 1]] # Normal Bluetooth scan - print("\nAttempting to scan now...") + blue = "\033[94m" + error = "\033[91m" + reset = "\033[0m" + print(f"\n{reset}Attempting to scan now{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("\nNo nearby devices found.") + print(f"\n{reset}[{error}+{reset}] No nearby devices found.") else: print("\nFound {} nearby device(s):".format(len(nearby_devices))) for idx, (addr, name, _) in enumerate(nearby_devices): @@ -138,18 +137,31 @@ def scan_for_devices(): known_devices += new_devices save_devices_to_file(known_devices) for idx, (addr, name) in enumerate(new_devices): - print(f"{idx + 1}: Device Name: {name}, Address: {addr}") + print(f"{reset}{idx + 1}{blue}: {blue}Device Name{reset}: {blue}{name}{reset}, {blue}Address{reset}: {blue}{addr}") return device_list +def getterm(): + size = os.get_terminal_size() + return size.columns + + def print_menu(): + blue = '\033[94m' + reset = "\033[0m" title = "BlueDucky - Bluetooth Device Attacker" - separator = "=" * 70 - print("\033[1;35m" + separator) # Purple color for separator - print("\033[1;33m" + title.center(len(separator))) # Yellow color for title - print("\033[1;35m" + separator + "\033[0m") # Purple color for separator - print("\033[1;32m" + "Remember, you can still attack devices without visibility..." + "\033[0m") - print("\033[1;32m" + "If you have their MAC address" + "\033[0m") - print("\033[1;35m" + separator + "\033[0m") # Purple color for separator + vertext = "Ver 2.1" + motd1 = f"Remember, you can still attack devices without visibility.." + motd2 = f"If you have their MAC address.." + 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(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 def main_menu(): clear_screen() @@ -178,3 +190,19 @@ def load_known_devices(filename='known_devices.txt'): return [tuple(line.strip().split(',')) for line in file] else: return [] + + +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