# 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](https://docs.platformio.org/en/latest/core/installation/index.html) (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: ```bash # /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: ```bash 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: ```bash pio run ``` PlatformIO will automatically download the required toolchain and Digistump framework on the first run. ## Uploading to the device ```bash 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: ```cpp #define LAYOUT_FRENCH // AZERTY #include ``` 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](https://usb.org/document-library/hid-usage-tables-15) specification (section 10, Keyboard/Keypad Page). ### Example: open a terminal on Linux and run a command ```cpp 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 |