Merge f6f016a4cc
into 2d37faf6cf
This commit is contained in:
commit
406c46da8d
78
BlueDucky.py
78
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
|
||||
|
@ -58,6 +51,8 @@ def setup_logging():
|
|||
# Set the logging level to INFO to filter out DEBUG messages
|
||||
logging.basicConfig(level=logging.INFO, handlers=[handler])
|
||||
|
||||
def print_error(msg):
|
||||
print(f"{color.RESET}[{color.RED}!{color.RESET}] {color.RED}CRITICAL ERROR{color.RESET}:{color.RESET}", msg)
|
||||
|
||||
class ConnectionFailureException(Exception):
|
||||
pass
|
||||
|
@ -267,20 +262,13 @@ 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}.")
|
||||
print_error(f"{color.RESET}Attempted Connection to {color.RED}{target_address} {color.RESET}was {color.RED}denied{color.RESET}.")
|
||||
return self.connected
|
||||
|
||||
|
||||
raise ConnectionFailureException(f"Connection failure on port {self.port}")
|
||||
|
||||
return self.connected
|
||||
|
||||
|
@ -640,36 +628,28 @@ 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("{reset}[{red}!{reset}] {red}CRITICAL{reset}: {blue}bluetoothctl {reset}is not installed or not working properly.")
|
||||
print_error(f"{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("{reset}[{red}!{reset}] {red}CRITICAL{reset}: No {blue}Bluetooth adapters{reset} have been detected.")
|
||||
print_error(f"No {color.BLUE}Bluetooth adapters{color.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
|
||||
log.warning(f"{color.RESET}Your {color.BLUE}Bluetooth devices{color.RESET} might not be supported.")
|
||||
|
||||
# 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()
|
||||
|
@ -685,17 +665,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:
|
||||
|
@ -705,10 +679,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.")
|
||||
|
||||
|
||||
|
||||
|
@ -731,7 +705,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()
|
||||
|
@ -740,12 +714,10 @@ def main():
|
|||
|
||||
finally:
|
||||
# unpair the target device
|
||||
blue = "\033[94m"
|
||||
reset = "\033[0m"
|
||||
|
||||
command = f'echo -e "remove {target_address}\n" | bluetoothctl'
|
||||
command = f'echo -e "\nremove {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()
|
||||
|
|
|
@ -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()
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue