Pico BadUSB is a simple implementation of the BadUSB idea. The features it has will certainly prove themselves in most of the less and more demanding tasks. What characterizes Pico BadUSB is a simple setup. Additionally, it uses a similar syntax as DuckyScript, so writing the payload will be more intuitive for experienced Rubber Ducky users.
If you want to learn more about the Raspberry Pi Pico, refer to the documentation or visit the website.
The program was created to emulate USB devices, particularly keyboards, for the purpose of automating tasks by executing prepared payloads. Pico BadUSB was designed for use with Raspberry Pi Pico boards, such as the Pico, Pico W and Pico 2, but the program should also work on most boards that support CircuitPython. The Pico BadUSB v2.0.0
release includes uf2
files, which are used for setup purposes. They contain a build of customized CircuitPython 9.2.0
with custom packages and filesystem initialization instructions for selected keyboard layouts such as QWERTY
, QWERTZ
and AZERTY
.
To correctly setup the device, hold the Boot Select BOOTSEL
button while plugging the micro USB
cable into the microcontroller. Once the device is detected by the system, drag and drop the uf2
file of your choice onto the media, e.g. pico-badusb.uf2
for the default QWERTY
layout. After a moment, the device will reappear in the system with all the necessary files ready to go.
If the board has been used before, it may be necessary to reset the device's Flash memory.
- Reset Flash memory if you have used the device before
- Hold down the
BOOTSEL
button while plugging in themicro USB
cable - Drag and drop the file
pico-badusb.uf2
onto the media - Wait for the drive to remount with the following files:
boot.py
boot_out.txt
main.py
payload.txt
license.txt
If you encounter a problem or if the selected uf2
file doesn't work, the source code is available in the pico-badusb directory. To run the program, prepare the board using Thonny IDE or your own work environment with CircuitPython. Then move the boot.py
, main.py
, and payload.txt
files to the root directory /
, and move the badusb
directory to the lib
subdirectory on the Raspberry Pi Pico drive.
Pico BadUSB supports both the standard QWERTY
keyboard layout and less common layouts like QWERTZ
and AZERTY
. Due to this variety, the table below contains the uf2
files for deployment on Raspberry Pi Pico boards.
Board | Layout | File | MD5 |
---|---|---|---|
Pico | QWERTY |
pico-badusb.uf2 | 78bd80bac2f451fd87a586460f52350c |
Pico W | QWERTY |
pico-badusb-w.uf2 | e53cef1f5bb97ca39ab976239854ada4 |
Pico 2 | QWERTY |
pico-badusb-2.uf2 | a8b9f56ab1c26579a7f5551b57accdbe |
Pico | QWERTZ |
pico-badusb-qwertz.uf2 | 662ccbcb6c9eab3b41ba6fa43aac6bd9 |
Pico W | QWERTZ |
pico-badusb-w-qwertz.uf2 | 2f4a04d8c68941d56648ab97785c09c2 |
Pico 2 | QWERTZ |
pico-badusb-2-qwertz.uf2 | 06263d2c851b2064a6e51800b1b4ab1a |
Pico | AZERTY |
pico-badusb-azerty.uf2 | bca8af6048141ccb382e4824c4049ec8 |
Pico W | AZERTY |
pico-badusb-w-azerty.uf2 | 99e63c5cd282ca5c87080b8d2f6e3748 |
Pico 2 | AZERTY |
pico-badusb-2-azerty.uf2 | aafad906286b0210efab990281b2deb5 |
In order to reset the flash memory of the device, simply hold down the BOOTSEL
button while plugging in the micro USB
cable. Then, drag and drop the file flash_nuke.uf2
onto the storage. The file can be downloaded from the Raspberry Pi website. If you don't see mass memory, make sure you removed the jumper link between pin GP1
and GND
.
The entire program is based on the content of the payload.txt
file, or another file, depending on whether you changed the path to the file in main.py
. The syntax must follow certain rules to execute correctly. In theory, the program will not stop when it detects a syntax error, instead, it will ignore the problematic code fragment, so make sure that the syntax is correct. Each time you save the payload.txt
file, its content will be automatically executed, so quickly remove the medium if you do not want to run the instructions on your computer or enable development mode.
Compared to DuckyScript, Pico BadUSB's syntax is significantly simplified, leaving only basic functions. Another difference is the inclusion of the keywords PRESS
and HOTKEY
, which are required before using keys like CONTROL
, ALT
, or DELETE
, as well as their combinations. Syntactically incorrect elements will be skipped but will not interfere with the execution of the program. Keywords such as commands and keycodes can be written with any combination of lowercase and uppercase letters.
Command | Description | Example |
---|---|---|
REM | Adds a comment | REM This is a comment |
DELAY | Adds a delay | DELAY 500 |
TYPESPEED | Changes the typing speed | TYPESPEED 100 |
PRESS | Alias to HOTKEY command |
PRESS ENTER |
HOTKEY | Enters key combination | HOTKEY GUI R |
STRING | Enters a string of ASCII characters | STRING This is a string |
LED | Turns on/off the onboard diode | LED ON |
This command is discretionary, in fact, to achieve the effect of a comment, it is sufficient to type anything at the beginning of the line that is not a keyword of the commands DELAY
, TYPESPEED
, PRESS
, HOTKEY
, STRING
, or LED
. After the fixed word, enter the content of the comment.
The DELAY
command defines the delay in milliseconds between individual payload instructions. If no value is defined, the default delay value of 500
milliseconds will be used.
TYPESPEED
defines the delay in milliseconds between the characters entered from the string sequence within the STRING
command. The default value is 0
, which means no delay.
After the keyword PRESS
, you can specify up to 6 keys, which can be provided as keycodes or as characters from the ASCII table. The keys are pressed in the order in which they are entered and released simultaneously. The PRESS
command is an alias for the HOTKEY
command.
After the keyword PRESS
, you can specify up to 6 keys, which can be provided as keycodes or as characters from the ASCII table. The keys are pressed in the order in which they are entered and released simultaneously.
The STRING
command converts the following string from the ASCII table (except for \n
and \r
) into a series of keystrokes. Make sure that when writing the payload, you do not include characters outside the ASCII table, otherwise, they will be ignored.
The command allows you to enable or disable the built-in LED. The command LED ON
is used to turn on the diode, and LED OFF
is used to turn it off. The keyword OFF
is discretionary, the LED will turn off if there is no additional value or if a value other than ON
is entered.
Keycodes allow you to refer to a key that cannot be represented as an ASCII character. Their use is only permitted in conjunction with the keywords PRESS
or HOTKEY
at the beginning of a line. For formality, they are written in capital letters, but the program will interpret them correctly even if they are written in lowercase.
UP
DOWN
LEFT
RIGHT
PAGEUP
PAGEDOWN
HOME
END
INSERT
DELETE
BACKSPACE
SPACE
TAB
ENTER
ESCAPE
PAUSE
PRINTSCREEN
MENU
F1
F2
F3
F4
F5
F6
F7
F8
F9
F10
F11
F12
SHIFT
CONTROL
CTRL
ALT
ALTGR
GUI
COMMAND
WINDOWS
CAPSLOCK
NUMLOCK
SCROLLOCK
The following example demonstrates the full functionality of Pico BadUSB. First, it activates the built-in LED, then, using Windows features, we open the defined link in the default browser. Finally, the LED turns off.
REM This is an example of a payload file
DELAY 1000
LED ON
HOTKEY GUI R
DELAY 500
STRING cmd.exe
PRESS ENTER
DELAY 500
STRING start https://youtu.be/dQw4w9WgXcQ
PRESS ENTER
LED OFF
The functionality of the Pico BadUSB tool can be extended by creating a physical connection between individual pins as well as by making custom changes within the module's source code.
In order to hide the visibility of the storage, the media memory can be turned off by shorting GP1
pin to ground GND
. It is recommended to connect GP1
pin in position 2
with GND
pin in position 3
, referring to the markings on the Raspberry Pi Pico pinout diagram.
If you encounter a problem and are sure that you have the jumpers connected properly, make sure that a file named boot.py
is available in storage with the following code.
from badusb.boot import Boot
# You can omit the if-else statement
if __name__ == "__main__":
Boot()
Since the contents of the payload.txt
file are executed each time it is saved, writing the payload may be difficult. For this reason, the ability to stop the payload execution has been added by shorting GP5
pin in position 7
with GND
pin in position 8
, referring to the markings on the Raspberry Pi Pico pinout diagram. As long as the pins are connected, the payload will not execute. Once the jumper is removed, the device will start executing the instructions contained in the payload.txt
file.
If you encounter a problem and are sure that you have the jumpers connected properly, make sure that a file named boot.py
is available in storage.
By using the source code, you can freely utilize the defined layouts QWERTY
, QWERTZ
, and AZERTY
by modifying the contents of the file keyboard.py
. To make changes, you must first import the appropriate layout with from .layouts import QWERTY
, and then assign its values to the ASCII
variable ASCII = QWERTY
within the Keyboard
class.
[1] Raspberry Pi Ltd. (2024). Raspberry Pi Pico Python SDK
[2] Raspberry Pi Ltd. (2024). Getting started with Raspberry Pi Pico
[3] Raspberry Pi Ltd. (2024). Raspberry Pi Pico Pinout
[4] MicroPython & CircuitPython contributors. (2024). Adafruit CircuitPython
[5] Scott Shawcroft. (2024). Adafruit HID library