This is the goal I am trying to accomplish:write a (simple) Rubber-Ducky script should write and run a Python `hello world’ script. However, since I am using macOS, I am creating a file called "Q4.py" and trying to write "Hello World!" in that python file. For reference, I was able to write my name "matt" in a .sh file with these exact files listed below, but I can't seem to get it to work for a python file.
For reference, this is my Q4.txt file which will print "Hello World!"
``DEFAULT_DELAY 500 STRING terminal ENTER DELAY 1000 STRING echo 'print("Hello, world!")' > /Users/matthewmcmurray/Downloads/Q4.py ENTER DELAY 500 STRING python3 /Users/matthewmcmurray/Downloads/Q4.py ENTER
The following below are my files for the python emulator:
`**duckProcess.py:**`
`from validation import LineCheck
from time import sleep
from inputSimulator import simulate_key_press, simulate_modified_key_stroke, simulate_text_entry
import os
defaultDelay = False
defaultDelayValue = 0
lastCommand = ""
lastKey = ""
isCapsEnabled = False
def SetDelay(delay:int):
global defaultDelay
global defaultDelayValue
if delay > 1:
defaultDelay = True
defaultDelayValue = delay
def ReadFile(filePath:str):
f = open(filePath)
duckyFile = f.read().splitlines()
f.close()
for line in duckyFile:
Calculate(line)
sleep(5)
if os.path.exists('/Users/tyran/Desktop/DuckyQ3.sh'):
print("File created successfully!")
else:
print("Failed to create the file.")
for line in duckyFile:
Calculate(line)
def Calculate(line:str):
command, keys = ProcessLine(line)
KeyboardAction(command, keys)
def CheckDefaultSleep():
if defaultDelay:
sleep(defaultDelayValue / 1000.0)
def SetLastCommand(command:str, keys:str):
global lastCommand
global lastKey
lastCommand, lastKey = command, keys
def ValidateCode(filePath : str):
f = open(filePath)
duckyFile = f.read().splitlines()
f.close()
for num, line in enumerate(duckyFile):
command, keys = ProcessLine(line)
result = LineCheck(command, keys, num+1)
if not result:
return False
return True
def KeyboardAction(command:str, keys:str):
global defaultDelay
global defaultDelayValue
global isCapsEnabled
keyboardKey = keys.upper()
try:
match command:
case "DEFAULT_DELAY" | "DEFAULTDELAY":
defaultDelay = True
defaultDelayValue += int(keys)
case "DELAY":
CheckDefaultSleep()
sleep(int(keys) / 1000.0)
case "STRING":
CheckDefaultSleep()
if isCapsEnabled:
simulate_text_entry(keys.upper())
else:
file_path = "/Users/matthewmcmurray/Downloads/Q3.sh"
with open(file_path, "a") as file:
file.write("Matt\n")
case "WINDOWS" | "GUI" | "ENTER" | "APP" | "MENU" | "SHIFT" | "ALT" | "CONTROL" | "CTRL":
CheckDefaultSleep()
simulate_modified_key_stroke(command, keys)
case "TAB" | "DELETE" | "SPACE" | "DOWNARROW" | "DOWN" | "LEFTARROW" | "LEFT" | "RIGHTARROW" | "RIGHT" | "UPARROW" | "UP":
CheckDefaultSleep()
simulate_key_press(command)
case "REPLAY":
CheckDefaultSleep()
for _ in range(int(keys)):
KeyboardAction(lastCommand, lastKey)
case "CAPS":
CheckDefaultSleep()
isCapsEnabled = not isCapsEnabled
except Exception as e:
print(e)
if command != "REPLAY" and command != "REM":
SetLastCommand(command, keys)
def ProcessLine(line):
words = line.split(' ')
command = words[0].upper() # Convert to uppercase for consistent matching
keys = " ".join(words[1:])
return command, keys
# Testing
if __name__ == "__main__":
'''KeyboardAction("DEFAULT_DELAY", "100")
KeyboardAction("STRING", "I am a bumbling fool")
KeyboardAction("WINDOWS", "")
KeyboardAction("DELAY", "1000")
KeyboardAction("WINDOWS", "")
KeyboardAction("ENTER", "")
KeyboardAction("SHIFT", "GUI")
KeyboardAction("SHIFT", "UPARROW")
KeyboardAction("REPLAY", "5")
KeyboardAction("SHIFT", "DOWNARROW")
KeyboardAction("SHIFT", "LEFTARROW")
KeyboardAction("SHIFT", "RIGHTARROW")
KeyboardAction("SHIFT", "p")
''' # This much is confirmed to work correctly
ValidateCode("helloworld.txt")`
`**inputSimulator.py:**`
`from pynput.keyboard import Key, Controller
from time import sleep
keyboard = Controller()
keys = {
"DELETE": Key.delete,
"SHIFT": Key.shift,
"CONTROL": Key.ctrl,
"CTRL": Key.ctrl,
"ENTER": Key.enter,
"HOME": Key.home,
"PAGEUP": Key.page_up,
"PAGEDOWN": Key.page_down,
"UPARROW": Key.up,
"UP": Key.up,
"LEFTARROW": Key.left,
"LEFT": Key.left,
"RIGHTARROW": Key.right,
"RIGHT": Key.right,
"DOWNARROW": Key.down,
"DOWN": Key.down,
"TAB": Key.tab,
"ESCAPE": Key.esc,
"ESC": Key.esc,
"ALT": Key.alt,
"END": Key.end,
"SPACE": " ", # Space key for macOS
"GUI": Key.cmd, # Command key for macOS
}
def simulate_modified_key_stroke(modifier_key, key):
if key in keys:
keyboard.press(keys[modifier_key])
keyboard.press(keys[key])
keyboard.release(keys[key])
keyboard.release(keys[modifier_key])
def simulate_key_press(key):
if key in keys:
keyboard.press(keys[key])
keyboard.release(keys[key])
def simulate_text_entry(text, delay=13/1000.0):
for char in text:
sleep(delay)
if char in keys:
keyboard.press(keys[char])
keyboard.release(keys[char])
else:
keyboard.press(char)
keyboard.release(char)
def text_to_keycode(*args):
result = []
for string in args:
if string.upper() in keys:
string = keys[string.upper()]
result.append(string)
return result`
`
**main.py:**`
`import argparse
from duckProcess import *
if __name__ == '__main__':
#parser = argparse.ArgumentParser(description='Testing out the main.')
#args = parser.parse_args()
filePath = input("Input path of DuckyScript: ")
with open(filePath, 'r') as f:
first_line = f.readline().strip() # strip to remove any potential newline or space
print(f"Reading command from line 1: '{first_line}'")
valid = ValidateCode(filePath)
if valid:
npt = input("Script has been validated. Execute? (Y/n) : ")
if npt == "Y" or npt == "y":
ReadFile(filePath)`
`**validation.py**`
`from time import sleep
validFKeys = ["F" + str(x) for x in range(1,13)]
validShiftKeys = ["DELETE", "HOME", "INSERT", "PAGEUP", "PAGEDOWN", "WINDOWS", "GUI", "UPARROW", "LEFTARROW", "RIGHTARROW", "TAB"]
validCTRLkeys = ["BREAK", "PAUSE", "ESCAPE", "ESC"]
validAltKeys = ["ALT", "END", "ESC", "ESCAPE", "SPACE", "TAB"]
def LineCheck(command:str, keys:str, currentLine:int):
match command:
case "REM":
pass
case "STRING":
if len(keys) <= 0:
print("Empty STRING command on line " + str(currentLine) + ".\n"
"This won't cause any errors, but it will not type anything.")
case "DEFAULT_DELAY" | "DEFAULTDELAY":
if not keys.isnumeric():
print(f"ERROR [Line = {currentLine}] |:: DEFAULTDELAY only accepts integer values.")
return False
elif currentLine != 1:
print(f"ERROR [Line = {currentLine}] |:: DEFAULTDELAY should only be present on line 1.")
return False
case "DELAY":
if not keys.isnumeric():
print("ERROR [Line = {line}] |:: DELAY only accepts integer values.".format(line=currentLine))
case "GUI":
if keys not in ["space", "r", ""]: # Add other acceptable keys if needed
print(f"ERROR [Line = {currentLine}] |:: Argument following GUI is not valid.")
return False
case "ENTER":
if len(keys) > 0:
print("ERROR [Line = {line}] |:: There is a command following ENTER. ENTER function doesn't support key combos.".format(line=currentLine))
case "APP" | "MENU":
if len(keys) > 0:
print("ERROR [Line = {line}] |:: There is a command following APP/MENU, which don't support key combos.".format(line=currentLine))
case "SHIFT":
if len(keys) > 0 and keys not in validShiftKeys:
print("ERROR [Line = {line}] |:: Command following SHIFT is not valid.".format(line=currentLine))
case "ALT":
if len(keys) > 0 and keys not in validAltKeys:
print("ERROR [Line = {line}] |:: Command following ALT is not valid.".format(line=currentLine))
case "CONTROL" | "CTRL":
if keys not in validCTRLkeys and keys not in validFKeys and len(keys) == 1 and not keys.isalpha():
print("ERROR [Line = {line}] |:: Command following {command} is not valid.".format(line=currentLine, command=command))
case "TAB":
if len(keys) > 0:
print("ERROR [Line = {line}] |:: There is a command following {command}.".format(line=currentLine, command=command))
case "DOWNARROW" | "DOWN":
if len(keys) > 0:
print("ERROR [Line = {line}] |:: There is a command following {command}.".format(line=currentLine, command=command))
case "LEFTARROW" | "LEFT":
if len(keys) > 0:
print("ERROR [Line = {line}] |:: There is a command following {command}.".format(line=currentLine, command=command))
case "RIGHTARROW" | "RIGHT":
if len(keys) > 0:
print("ERROR [Line = {line}] |:: There is a command following {command}.".format(line=currentLine, command=command))
case "UPARROW" | "UP":
if len(keys) > 0:
print("ERROR [Line = {line}] |:: There is a command following {command}.".format(line=currentLine, command=command))
case "REPLAY":
if not keys.isnumeric():
print("ERROR [Line = {line}] |:: REPLAY only accepts integers.".format(line=currentLine))
case "DELETE":
if len(keys) > 0:
print("ERROR [Line = {line}] |:: There is a command following {command}.".format(line=currentLine, command=command))
case "CAPS":
if len(keys) > 0:
print("ERROR [Line = {line}] |:: There is a command following {command}.".format(line=currentLine, command=command))
case "SPACE":
if len(keys) > 0:
print("ERROR [Line = {line}] |:: There is a command following {command}.".format(line=currentLine,command=command))
return False
case _:
print(f"ERROR [Line = {currentLine}] |:: Command '{command}' not recognized.")
return False
return True
when running "python3 main.py", it asked me for the input file as expected, "Input path of DuckyScript:", and i inputted Q4.txt. It went through and processed each line, and completed, but at the end the Q4.py file was not updated to have 'Hello World!' in it. I'm not sure why this is happening. Any help would be appreciated!
For more information, my Q4.py is a file in my Downloads directory, and my WorkingPrototype2 folder with the file in it is inside of the Downloads directory as well.