import os, bluetooth, re, subprocess, time, curses import logging as log ########################## # 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}> ") if target_address == "": devices = scan_for_devices() if devices: # Check if the returned list is from known devices or scanned devices 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() if confirm == 'y' or confirm == 'yes': return devices[0][0] elif confirm != 'y' or 'yes': return 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 if 0 <= selection < len(devices): target_address = devices[selection][0] else: print("\nInvalid selection. Exiting.") return else: return elif not is_valid_mac_address(target_address): print("\nInvalid MAC address format. Please enter a valid MAC address.") return return target_address def restart_bluetooth_daemon(): run(["sudo", "service", "bluetooth", "restart"]) time.sleep(0.5) def run(command): assert(isinstance(command, list)) log.info("executing '%s'" % " ".join(command)) result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) return result def print_fancy_ascii_art(): ascii_art = """ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠄⠒⠒⠒⠒⠒⠒⠂⠠⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠴⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠓⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠞⠁⠀⠀⠀⠀⣀⡤⠴⠒⠒⠒⠒⠦⠤⣀⠀⠀⠀⠙⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⢰⠋⠀⠀⠀⣠⠖⠋⢀⣄⣀⡀⠀⠀⠀⠀⠀⠀⠉⠲⣄⠀⠈⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⢠⠇⠀⠀⢀⡼⠁⠀⣴⣿⡛⠻⣿⣧⡀⠀⠀⠀⠀⠀⠀⠈⠳⡄⡿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⣼⣀⣀⣀⡜⠀⠀⠀⣿⣿⣿⣿⣿⣿⡧⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⣀⡤⠟⠁⠀⠈⠙⡶⣄⡀⠈⠻⢿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠇⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⣤⣤⠖⠖⠛⠉⠈⣀⣀⠀⠴⠊⠀⠀⣹⣷⣶⡏⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⣀⡀⠀⠀ ⠘⠿⣿⣷⣶⣶⣶⣶⣤⣶⣶⣶⣿⣿⣿⡿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡜⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⠤⠖⠒⠋⠉⠁⠙⣆⠀ ⠀⠀⠀⠀⠉⠉⠉⠉⠙⠿⣍⣩⠟⠋⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣾⣖⣶⣶⢾⠯⠽⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡄ ⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⠚⠁⠀⠀⠀⠀⠈⠓⠤⠀⠀⠀⠀⠀⠀⠐⠒⠚⠉⠉⠁⠀⠀⠀⠀⠀⠀⢀⣀⣀⠀⣀⢀⠀⠀⠀⠀⠀⠀⠀⣇ ⠀⠀⠀⠀⠀⠀⠀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⠤⠤⠖⠒⠚⠉⠉⠁⠀⠀⠀⢸⢸⣦⠀⠀⠀⠀⠀⠀⢸ ⠀⠀⠀⠀⠀⢠⠎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⡠⠤⠴⠒⠒⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡏⣸⡏⠇⠀⠀⠀⠀⠀⢸ ⠀⠀⠀⠀⢠⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠞⢠⡿⠀⠀⠀⠀⠀⠀⠀⢸ ⠀⠀⠀⠀⣾⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠊⣠⡟⠀⠀⠀⠀⠀⠀⠀⠀⡏ ⠀⠀⠀⠀⡏⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠖⠉⢀⣴⠏⠠⠀⠀⠀⠀⠀⠀⠀⣸⠁ ⠀⠀⠀⠀⢹⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠒⠒⠢⠤⠄⠀⠀⠀⠀⠀⠈⠁⠀⣠⣶⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⢠⠃⠀ ⠀⠀⠀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣴⠿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠃⠀⠀ ⠀⠀⠀⠀⠀⠈⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⡶⠿⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠃⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠳⣄⢀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠤⠖⣪⡵⠋⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠈⠑⠫⠭⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣭⣭⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⡴⠶⠛⠉⠀⠀⠀⠀⠀⠀⠀ """ print("\033[94m" + ascii_art + "\033[0m") # Blue color def clear_screen(): os.system('clear') # Function to save discovered devices to a file def save_devices_to_file(devices, filename='known_devices.txt'): with open(filename, 'w') as file: for addr, name in devices: file.write(f"{addr},{name}\n") # 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: blue = "\033[94m" error = "\033[91m" reset = "\033[0m" print(f"\n{reset}Known devices{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}") 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(f"{reset}Enter the index number of the device to attack{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}...") 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.") else: print("\nFound {} nearby device(s):".format(len(nearby_devices))) for idx, (addr, name, _) in enumerate(nearby_devices): device_list.append((addr, name)) # Save the scanned devices only if they are not already in known devices new_devices = [device for device in device_list if device not in known_devices] if new_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}") 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" 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() print_fancy_ascii_art() print_menu() def is_valid_mac_address(mac_address): # Regular expression to match a MAC address in the form XX:XX:XX:XX:XX:XX mac_address_pattern = re.compile(r'^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$') return mac_address_pattern.match(mac_address) is not None # Function to read DuckyScript from file def read_duckyscript(filename): if os.path.exists(filename): with open(filename, 'r') as file: return [line.strip() for line in file.readlines()] else: log.warning(f"File {filename} not found. Skipping DuckyScript.") return None # Function to load known devices from a file def load_known_devices(filename='known_devices.txt'): if os.path.exists(filename): with open(filename, 'r') as file: 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