4.8 KiB
Digispark USB Rubber Ducky PoC
A proof-of-concept USB HID keystroke injection tool using a Digispark ATtiny85 development board and PlatformIO.
When plugged into a host machine the device emulates a USB keyboard and automatically types a predefined payload.
Prerequisites
- PlatformIO CLI (or the PlatformIO IDE extension for VS Code)
- A Digispark ATtiny85 board with the micronucleus bootloader
On Linux you may also need udev rules so the micronucleus uploader can access the USB device without root:
# /etc/udev/rules.d/49-micronucleus.rules
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE="0660", GROUP="plugdev"
Reload rules after creating the file:
sudo udevadm control --reload-rules && sudo udevadm trigger
Project structure
.
├── platformio.ini # Board & framework configuration
├── src/
│ └── main.cpp # Payload source code
├── include/ # Project header files
├── lib/ # Private libraries
└── test/ # Unit tests
Building
Compile the firmware:
pio run
PlatformIO will automatically download the required toolchain and Digistump framework on the first run.
Uploading to the device
pio run -t upload
The console will print Plug in device now.... You then have 60 seconds to connect the Digispark to a USB port. The micronucleus bootloader on the board will receive the firmware and reboot into the payload automatically.
Tip: If the upload times out, unplug the board, run the command again and re-plug when prompted.
Adapting the payload
All payload logic lives in the setup() function inside src/main.cpp, between the --- payload start --- and --- payload end --- comments.
Keyboard layout
The layout is selected with a #define before the DigiKeyboard.h include:
#define LAYOUT_FRENCH // AZERTY
#include <DigiKeyboard.h>
Available layouts (define exactly one):
| Define | Layout |
|---|---|
LAYOUT_US_ENGLISH |
US QWERTY (default if none specified) |
LAYOUT_FRENCH |
French AZERTY |
LAYOUT_FRENCH_BELGIAN |
Belgian AZERTY |
LAYOUT_FRENCH_SWISS |
Swiss French |
LAYOUT_CANADIAN_FRENCH |
Canadian French |
LAYOUT_CANADIAN_MULTILINGUAL |
Canadian Multilingual |
LAYOUT_GERMAN |
German QWERTZ |
LAYOUT_GERMAN_SWISS |
Swiss German |
LAYOUT_SPANISH |
Spanish |
LAYOUT_SPANISH_LATIN_AMERICA |
Latin American Spanish |
LAYOUT_ITALIAN |
Italian |
LAYOUT_PORTUGUESE |
Portuguese |
LAYOUT_PORTUGUESE_BRAZILIAN |
Brazilian Portuguese |
LAYOUT_DANISH |
Danish |
LAYOUT_FINNISH |
Finnish |
LAYOUT_NORWEGIAN |
Norwegian |
LAYOUT_SWEDISH |
Swedish |
LAYOUT_TURKISH |
Turkish |
LAYOUT_UNITED_KINGDOM |
UK |
LAYOUT_ICELANDIC |
Icelandic |
LAYOUT_IRISH |
Irish |
Useful API
| Function | Description |
|---|---|
DigiKeyboard.print("text") |
Type a string |
DigiKeyboard.println("text") |
Type a string followed by Enter |
DigiKeyboard.sendKeyStroke(key) |
Send a single key press |
DigiKeyboard.sendKeyStroke(key, modifier) |
Send a key press with a modifier |
DigiKeyboard.delay(ms) |
Wait (also keeps USB alive) |
Common modifier constants: MOD_SHIFT_LEFT, MOD_CONTROL_LEFT, MOD_ALT_LEFT, MOD_GUI_LEFT (Windows/Super key).
Common key codes (USB HID usage IDs):
| Code | Key |
|---|---|
0x04..0x1D |
a..z |
0x1E..0x27 |
1..0 |
40 |
Enter |
41 |
Escape |
43 |
Tab |
44 |
Space |
The full list is in the USB HID usage tables specification (section 10, Keyboard/Keypad Page).
Example: open a terminal on Linux and run a command
void setup() {
DigiKeyboard.delay(2000);
// Ctrl+Alt+T opens a terminal on most Linux desktops
DigiKeyboard.sendKeyStroke(0x17, MOD_CONTROL_LEFT | MOD_ALT_LEFT); // 't'
DigiKeyboard.delay(1000);
DigiKeyboard.println("echo 'Hello from Digispark!'");
}
Hardware constraints
| Resource | Total | Used by current payload |
|---|---|---|
| Flash | 6 012 bytes | ~2 860 bytes (48%) |
| RAM | 512 bytes | ~104 bytes (20%) |
The micronucleus bootloader occupies roughly 2 KB of the 8 KB total flash, leaving ~6 KB for application code. Keep payloads concise, especially long strings.
Troubleshooting
| Problem | Solution |
|---|---|
Upload failed: cannot access USB device |
Add udev rules (see Prerequisites) or run with sudo |
| Upload times out | Unplug the board, run pio run -t upload again, plug in when prompted |
| Wrong characters appear on the host | Change the LAYOUT_* define to match the host OS keyboard layout |
| Payload runs too fast / host misses keystrokes | Increase DigiKeyboard.delay() values between actions |