4 Commits

Author SHA1 Message Date
Dave
68b1262227 Refactor script running to support long delays without blocking webservice 2023-09-17 14:48:46 -05:00
Dave
74ef11770b Clarify getting latest release 2023-06-24 13:07:19 -05:00
Dave
a7992c2fb3 Update installation instructions 2023-06-24 12:58:58 -05:00
Dave
49e81125c1 Updated issue template 2023-06-24 10:01:39 -05:00
5 changed files with 119 additions and 34 deletions

View File

@@ -19,5 +19,11 @@ A clear and concise description of what you expected to happen.
**Screenshots** **Screenshots**
If applicable, add screenshots to help explain your problem. If applicable, add screenshots to help explain your problem.
**Debug info**
If possible, include debug serial data.
On Windows, use PuTTY, connect to the debug serial port (commonly COM3, but could vary)
On Linux, use minicom (minicom -b 115200 -o -D /dev/ttyACM0, where ttyACM0 corresponds to your device)
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.

View File

@@ -16,7 +16,61 @@
<br /> <br />
## Install ## Quick Start Guide
Install and have your USB Rubber Ducky working in less than 5 minutes.
1. Download the latest release from the [Releases](https://github.com/dbisu/pico-ducky/releases) page.
2. Plug the device into a USB port while holding the boot button. It will show up as a removable media device named RPI-RP2.
3. Install CircutlPython on the Pico or Pico W
If using a Pico board:
Copy the adafruit-circuitpython-raspberry_pi_pico-en_US-8.0.0.uf2 file to the root of the Pico (RPI-RP2). The device will reboot and after a second or so, it will reconnect as CIRCUITPY.
If using a Pico W board:
Copy the adafruit-circuitpython-raspberry_pi_pico_w-en_US-8.0.0.uf2 file to the root of the Pico (RPI-RP2). The device will reboot and after a second or so, it will reconnect as CIRCUITPY.
4. Copy the lib folder to the root of the CIRCUITPY
5. Copy *.py to the root of the CIRCUITPY
6. Follow the instructions in README.md to enter setup mode
7. Copy your payload as payload.dd to the root of the CIRCUITPY
8. Unplug the device from the USB port and remove the setup jumper.
Enjoy your Pico-Ducky.
## Setup mode
To edit the payload, enter setup mode by connecting the pin 1 (`GP0`) to pin 3 (`GND`), this will stop the pico-ducky from injecting the payload in your own machine.
The easiest way to do so is by using a jumper wire between those pins as seen bellow.
![Setup mode with a jumper](images/setup-mode.png)
## USB enable/disable mode
If you need the pico-ducky to not show up as a USB mass storage device for stealth, follow these instructions.
- Enter setup mode.
- Copy your payload script to the pico-ducky.
- Disconnect the pico from your host PC.
- Connect a jumper wire between pin 18 (`GND`) and pin 20 (`GPIO15`).
This will prevent the pico-ducky from showing up as a USB drive when plugged into the target computer.
- Remove the jumper and reconnect to your PC to reprogram.
Pico: The default mode is USB mass storage enabled.
Pico W: The default mode is USB mass storage **disabled**
![USB enable/disable mode](images/usb-boot-mode.png)
-----
# Full Install Instructions
Install and have your USB Rubber Ducky working in less than 5 minutes. Install and have your USB Rubber Ducky working in less than 5 minutes.
@@ -70,14 +124,14 @@ API endpoints
/api/run/<filenumber> /api/run/<filenumber>
``` ```
### Setup mode ## Setup mode
To edit the payload, enter setup mode by connecting the pin 1 (`GP0`) to pin 3 (`GND`), this will stop the pico-ducky from injecting the payload in your own machine. To edit the payload, enter setup mode by connecting the pin 1 (`GP0`) to pin 3 (`GND`), this will stop the pico-ducky from injecting the payload in your own machine.
The easiest way to do so is by using a jumper wire between those pins as seen bellow. The easiest way to do so is by using a jumper wire between those pins as seen bellow.
![Setup mode with a jumper](images/setup-mode.png) ![Setup mode with a jumper](images/setup-mode.png)
### USB enable/disable mode ## USB enable/disable mode
If you need the pico-ducky to not show up as a USB mass storage device for stealth, follow these instructions. If you need the pico-ducky to not show up as a USB mass storage device for stealth, follow these instructions.
- Enter setup mode. - Enter setup mode.
@@ -92,7 +146,7 @@ Pico W: The default mode is USB mass storage **disabled**
![USB enable/disable mode](images/usb-boot-mode.png) ![USB enable/disable mode](images/usb-boot-mode.png)
### Multiple payloads ## Multiple payloads
Multiple payloads can be stored on the Pico and Pico W. Multiple payloads can be stored on the Pico and Pico W.
To select a payload, ground one of these pins: To select a payload, ground one of these pins:
@@ -101,7 +155,7 @@ To select a payload, ground one of these pins:
- GP10 - payload3.dd - GP10 - payload3.dd
- GP11 - payload4.dd - GP11 - payload4.dd
### Changing Keyboard Layouts ## Changing Keyboard Layouts
Copied from [Neradoc/Circuitpython_Keyboard_Layouts](https://github.com/Neradoc/Circuitpython_Keyboard_Layouts/blob/main/PICODUCKY.md) Copied from [Neradoc/Circuitpython_Keyboard_Layouts](https://github.com/Neradoc/Circuitpython_Keyboard_Layouts/blob/main/PICODUCKY.md)

View File

@@ -11,6 +11,7 @@ import time
import digitalio import digitalio
from board import * from board import *
import board import board
import duckyinpython
from duckyinpython import * from duckyinpython import *
if(board.board_id == 'raspberry_pi_pico_w'): if(board.board_id == 'raspberry_pi_pico_w'):
import wifi import wifi
@@ -56,7 +57,8 @@ if(progStatus == False):
# not in setup mode, inject the payload # not in setup mode, inject the payload
payload = selectPayload() payload = selectPayload()
print("Running ", payload) print("Running ", payload)
runScript(payload) #runScript(payload)
duckyinpython.fileToRun = payload
print("Done") print("Done")
else: else:
@@ -68,15 +70,16 @@ async def main_loop():
global led,button1 global led,button1
button_task = asyncio.create_task(monitor_buttons(button1)) button_task = asyncio.create_task(monitor_buttons(button1))
script_task = asyncio.create_task(runScriptTask())
if(board.board_id == 'raspberry_pi_pico_w'): if(board.board_id == 'raspberry_pi_pico_w'):
pico_led_task = asyncio.create_task(blink_pico_w_led(led)) pico_led_task = asyncio.create_task(blink_pico_w_led(led))
print("Starting Wifi") print("Starting Wifi")
startWiFi() startWiFi()
print("Starting Web Service") print("Starting Web Service")
webservice_task = asyncio.create_task(startWebService()) webservice_task = asyncio.create_task(startWebService())
await asyncio.gather(pico_led_task, button_task, webservice_task) await asyncio.gather(pico_led_task, button_task, webservice_task, script_task)
else: else:
pico_led_task = asyncio.create_task(blink_pico_led(led)) pico_led_task = asyncio.create_task(blink_pico_led(led))
await asyncio.gather(pico_led_task, button_task) await asyncio.gather(pico_led_task, button_task, script_task)
asyncio.run(main_loop()) asyncio.run(main_loop())

View File

@@ -80,8 +80,8 @@ def parseLine(line):
if(line[0:3] == "REM"): if(line[0:3] == "REM"):
# ignore ducky script comments # ignore ducky script comments
pass pass
elif(line[0:5] == "DELAY"): #elif(line[0:5] == "DELAY"):
time.sleep(float(line[6:])/1000) # time.sleep(float(line[6:])/1000)
elif(line[0:6] == "STRING"): elif(line[0:6] == "STRING"):
sendString(line[7:]) sendString(line[7:])
elif(line[0:5] == "PRINT"): elif(line[0:5] == "PRINT"):
@@ -133,26 +133,44 @@ def getProgrammingStatus():
defaultDelay = 0 defaultDelay = 0
def runScript(file): async def runScriptTask():
global defaultDelay global defaultDelay, fileToRun
print("starting runScript")
while True:
#print("Checking for file", fileToRun)
if fileToRun is not None:
duckyScriptPath = fileToRun
print("starting",duckyScriptPath)
with open(duckyScriptPath,"r",encoding='utf-8') as f:
duckyScriptPath = file previousLine = ""
try: for line in f:
f = open(duckyScriptPath,"r",encoding='utf-8') line = line.rstrip()
previousLine = "" if(line[0:6] == "REPEAT"):
for line in f: for i in range(int(line[7:])):
line = line.rstrip() #repeat the last command
if(line[0:6] == "REPEAT"): parseLine(previousLine)
for i in range(int(line[7:])): await asyncio.sleep_ms(defaultDelay)
#repeat the last command elif(line[0:5] == "DELAY"):
parseLine(previousLine) delay = int(line[6:])
time.sleep(float(defaultDelay)/1000) #print("sleeping for ",delay)
else: #print(type(delay))
parseLine(line) await asyncio.sleep_ms(delay)
previousLine = line previousLine = line
time.sleep(float(defaultDelay)/1000) else:
except OSError as e: #print("parsing line", line)
print("Unable to open file ", file) parseLine(line)
previousLine = line
#print("sleeping",defaultDelay)
await asyncio.sleep_ms(defaultDelay)
#print("done sleeping")
print("ending",duckyScriptPath)
fileToRun = None
await asyncio.sleep(1)
print("ending runScript")
def selectPayload(): def selectPayload():
global payload1Pin, payload2Pin, payload3Pin, payload4Pin global payload1Pin, payload2Pin, payload3Pin, payload4Pin
@@ -234,7 +252,7 @@ async def blink_pico_w_led(led):
await asyncio.sleep(0.5) await asyncio.sleep(0.5)
async def monitor_buttons(button1): async def monitor_buttons(button1):
global inBlinkeyMode, inMenu, enableRandomBeep, enableSirenMode,pixel global inBlinkeyMode, inMenu, enableRandomBeep, enableSirenMode,pixel, fileToRun
print("starting monitor_buttons") print("starting monitor_buttons")
button1Down = False button1Down = False
while True: while True:
@@ -257,7 +275,8 @@ async def monitor_buttons(button1):
# Run selected payload # Run selected payload
payload = selectPayload() payload = selectPayload()
print("Running ", payload) print("Running ", payload)
runScript(payload) #runScript(payload)
fileToRun = payload
print("Done") print("Done")
button1Down = False button1Down = False

View File

@@ -12,6 +12,7 @@ import wsgiserver as server
from adafruit_wsgi.wsgi_app import WSGIApp from adafruit_wsgi.wsgi_app import WSGIApp
import wifi import wifi
import duckyinpython
from duckyinpython import * from duckyinpython import *
payload_html = """<!DOCTYPE html> payload_html = """<!DOCTYPE html>
@@ -209,7 +210,8 @@ def run_script(request, filename):
print("run_script ", filename) print("run_script ", filename)
response = response_html.format("Running script " + filename) response = response_html.format("Running script " + filename)
#print(response) #print(response)
runScript(filename) #runScript(filename)
duckyinpython.fileToRun = filename
return("200 OK",[('Content-Type', 'text/html')], response) return("200 OK",[('Content-Type', 'text/html')], response)
@web_app.route("/") @web_app.route("/")
@@ -223,7 +225,8 @@ def run_script(request, filenumber):
print("run_script ", filenumber) print("run_script ", filenumber)
response = response_html.format("Running script " + filename) response = response_html.format("Running script " + filename)
#print(response) #print(response)
runScript(filename) #runScript(filename)
duckyinpython.fileToRun = filename
return("200 OK",[('Content-Type', 'text/html')], response) return("200 OK",[('Content-Type', 'text/html')], response)
async def startWebService(): async def startWebService():