2024-05-15 23:15:55 +00:00
import os , bluetooth , re , subprocess , time , curses
2024-01-17 01:21:35 +00:00
import logging as log
2024-05-15 23:15:55 +00:00
##########################
# UI Redesign by Lamento #
##########################
2024-01-17 01:21:35 +00:00
def get_target_address ( ) :
2024-05-15 23:15:55 +00:00
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 } > " )
2024-01-19 08:55:44 +00:00
2024-01-17 01:21:35 +00:00
if target_address == " " :
devices = scan_for_devices ( )
if devices :
2024-01-19 08:55:44 +00:00
# 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
2024-04-07 15:53:20 +00:00
# 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.
2024-05-15 23:15:55 +00:00
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 ( )
2024-04-07 15:53:20 +00:00
if confirm == ' y ' or confirm == ' yes ' :
return devices [ 0 ] [ 0 ]
elif confirm != ' y ' or ' yes ' :
return
2024-01-19 08:55:44 +00:00
else :
# Show list of scanned devices for user selection
for idx , ( addr , name ) in enumerate ( devices ) :
2024-05-15 23:15:55 +00:00
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
2024-01-17 01:21:35 +00:00
if 0 < = selection < len ( devices ) :
target_address = devices [ selection ] [ 0 ]
else :
print ( " \n Invalid selection. Exiting. " )
return
else :
return
elif not is_valid_mac_address ( target_address ) :
print ( " \n Invalid MAC address format. Please enter a valid MAC address. " )
return
2024-01-19 08:55:44 +00:00
2024-01-17 01:21:35 +00:00
return target_address
def restart_bluetooth_daemon ( ) :
run ( [ " sudo " , " service " , " bluetooth " , " restart " ] )
time . sleep ( 0.5 )
def run ( command ) :
assert ( isinstance ( command , list ) )
2024-01-19 08:55:44 +00:00
log . info ( " executing ' %s ' " % " " . join ( command ) )
2024-01-17 01:21:35 +00:00
result = subprocess . run ( command , stdout = subprocess . PIPE , stderr = subprocess . PIPE , text = True )
return result
2024-01-19 09:02:36 +00:00
def print_fancy_ascii_art ( ) :
2024-01-17 01:21:35 +00:00
ascii_art = """
2024-05-15 23:15:55 +00:00
⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⣀ ⠤ ⠄ ⠒ ⠒ ⠒ ⠒ ⠒ ⠒ ⠂ ⠠ ⢄ ⡀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀
⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⣀ ⠴ ⠋ ⠁ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠉ ⠓ ⢄ ⡀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀
⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢠ ⠞ ⠁ ⠀ ⠀ ⠀ ⠀ ⣀ ⡤ ⠴ ⠒ ⠒ ⠒ ⠒ ⠦ ⠤ ⣀ ⠀ ⠀ ⠀ ⠙ ⢆ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀
⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢰ ⠋ ⠀ ⠀ ⠀ ⣠ ⠖ ⠋ ⢀ ⣄ ⣀ ⡀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠉ ⠲ ⣄ ⠀ ⠈ ⣧ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀
⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢠ ⠇ ⠀ ⠀ ⢀ ⡼ ⠁ ⠀ ⣴ ⣿ ⡛ ⠻ ⣿ ⣧ ⡀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠈ ⠳ ⡄ ⡿ ⡆ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀
⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⣼ ⣀ ⣀ ⣀ ⡜ ⠀ ⠀ ⠀ ⣿ ⣿ ⣿ ⣿ ⣿ ⣿ ⡧ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠙ ⣿ ⣷ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀
⠀ ⠀ ⠀ ⠀ ⠀ ⣀ ⡤ ⠟ ⠁ ⠀ ⠈ ⠙ ⡶ ⣄ ⡀ ⠈ ⠻ ⢿ ⣿ ⡿ ⠋ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠇ ⡿ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀
⣤ ⣤ ⠖ ⠖ ⠛ ⠉ ⠈ ⣀ ⣀ ⠀ ⠴ ⠊ ⠀ ⠀ ⣹ ⣷ ⣶ ⡏ ⠉ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⡇ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⣀ ⡀ ⠀ ⠀
⠘ ⠿ ⣿ ⣷ ⣶ ⣶ ⣶ ⣶ ⣤ ⣶ ⣶ ⣶ ⣿ ⣿ ⣿ ⡿ ⠟ ⠁ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⡜ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⣀ ⣠ ⣤ ⠤ ⠖ ⠒ ⠋ ⠉ ⠁ ⠙ ⣆ ⠀
⠀ ⠀ ⠀ ⠀ ⠉ ⠉ ⠉ ⠉ ⠙ ⠿ ⣍ ⣩ ⠟ ⠋ ⠙ ⢦ ⡀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⣠ ⣾ ⣖ ⣶ ⣶ ⢾ ⠯ ⠽ ⠛ ⠋ ⠁ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠸ ⡄
⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⣤ ⠚ ⠁ ⠀ ⠀ ⠀ ⠀ ⠈ ⠓ ⠤ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠐ ⠒ ⠚ ⠉ ⠉ ⠁ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⣀ ⣀ ⠀ ⣀ ⢀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⣇
⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⡴ ⠋ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⣀ ⣀ ⠤ ⠤ ⠖ ⠒ ⠚ ⠉ ⠉ ⠁ ⠀ ⠀ ⠀ ⢸ ⢸ ⣦ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢸
⠀ ⠀ ⠀ ⠀ ⠀ ⢠ ⠎ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⣀ ⡠ ⠤ ⠴ ⠒ ⠒ ⠉ ⠉ ⠁ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⡏ ⣸ ⡏ ⠇ ⠀ ⠀ ⠀ ⠀ ⠀ ⢸
⠀ ⠀ ⠀ ⠀ ⢠ ⠇ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢻ ⡀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⠞ ⢠ ⡿ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢸
⠀ ⠀ ⠀ ⠀ ⣾ ⡀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠹ ⣄ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⡠ ⠊ ⣠ ⡟ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⡏
⠀ ⠀ ⠀ ⠀ ⡏ ⠁ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠈ ⠢ ⣄ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⡠ ⠖ ⠉ ⢀ ⣴ ⠏ ⠠ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⣸ ⠁
⠀ ⠀ ⠀ ⠀ ⢹ ⡀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠉ ⠒ ⠒ ⠢ ⠤ ⠄ ⠀ ⠀ ⠀ ⠀ ⠀ ⠈ ⠁ ⠀ ⣠ ⣶ ⠟ ⠁ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢠ ⠃ ⠀
⠀ ⠀ ⠀ ⠀ ⠀ ⢣ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⣀ ⣤ ⣴ ⠿ ⠛ ⠁ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⣠ ⠃ ⠀ ⠀
⠀ ⠀ ⠀ ⠀ ⠀ ⠈ ⢧ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⣀ ⣤ ⡶ ⠿ ⠛ ⠉ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⢀ ⡴ ⠃ ⠀ ⠀ ⠀
⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠳ ⣄ ⢀ ⣀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠈ ⠉ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠤ ⠖ ⣪ ⡵ ⠋ ⠀ ⠀ ⠀ ⠀ ⠀
⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠈ ⠑ ⠫ ⠭ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣭ ⣭ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⣤ ⡴ ⠶ ⠛ ⠉ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀ ⠀
"""
print ( " \033 [94m " + ascii_art + " \033 [0m " ) # Blue color
2024-01-17 01:21:35 +00:00
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 ( )
2024-05-15 23:15:55 +00:00
blue = " \033 [94m "
error = " \033 [91m "
reset = " \033 [0m "
2024-01-17 01:21:35 +00:00
# Load known devices
known_devices = load_known_devices ( )
if known_devices :
2024-05-15 23:15:55 +00:00
blue = " \033 [94m "
error = " \033 [91m "
reset = " \033 [0m "
print ( f " \n { reset } Known devices { blue } : " )
2024-01-17 01:21:35 +00:00
for idx , ( addr , name ) in enumerate ( known_devices ) :
2024-05-15 23:15:55 +00:00
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 } ): " )
2024-01-17 01:21:35 +00:00
if use_known_device . lower ( ) == ' yes ' :
2024-05-15 23:15:55 +00:00
device_choice = int ( input ( f " { reset } Enter the index number of the device to attack { blue } : " ) )
2024-01-17 01:21:35 +00:00
return [ known_devices [ device_choice - 1 ] ]
# Normal Bluetooth scan
2024-05-15 23:15:55 +00:00
blue = " \033 [94m "
error = " \033 [91m "
reset = " \033 [0m "
print ( f " \n { reset } Attempting to scan now { blue } ... " )
2024-01-17 01:21:35 +00:00
nearby_devices = bluetooth . discover_devices ( duration = 8 , lookup_names = True , flush_cache = True , lookup_class = True )
device_list = [ ]
if len ( nearby_devices ) == 0 :
2024-05-15 23:15:55 +00:00
print ( f " \n { reset } [ { error } + { reset } ] No nearby devices found. " )
2024-01-17 01:21:35 +00:00
else :
print ( " \n Found {} 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 )
2024-02-05 20:22:13 +00:00
for idx , ( addr , name ) in enumerate ( new_devices ) :
2024-05-15 23:15:55 +00:00
print ( f " { reset } { idx + 1 } { blue } : { blue } Device Name { reset } : { blue } { name } { reset } , { blue } Address { reset } : { blue } { addr } " )
2024-01-17 01:21:35 +00:00
return device_list
2024-05-15 23:15:55 +00:00
def getterm ( ) :
size = os . get_terminal_size ( )
return size . columns
2024-01-19 09:02:36 +00:00
def print_menu ( ) :
2024-05-15 23:15:55 +00:00
blue = ' \033 [94m '
reset = " \033 [0m "
2024-01-19 09:02:36 +00:00
title = " BlueDucky - Bluetooth Device Attacker "
2024-05-15 23:15:55 +00:00
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
2024-01-19 09:02:36 +00:00
2024-01-17 01:21:35 +00:00
def main_menu ( ) :
clear_screen ( )
2024-01-19 09:02:36 +00:00
print_fancy_ascii_art ( )
print_menu ( )
2024-01-17 01:21:35 +00:00
2024-04-07 15:53:20 +00:00
2024-01-17 01:21:35 +00:00
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
2024-04-07 15:53:20 +00:00
def read_duckyscript ( filename ) :
2024-01-17 01:21:35 +00:00
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 [ ]
2024-05-15 23:15:55 +00:00
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