├── pico-badusb ├── badusb │ ├── __init__.py │ ├── layouts │ │ ├── __init__.py │ │ ├── azerty.py │ │ ├── qwerty.py │ │ └── qwertz.py │ ├── boot.py │ ├── keyboard.py │ └── command.py ├── boot.py ├── main.py └── payload.txt ├── LICENSE └── README.md /pico-badusb/badusb/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pico-badusb/badusb/layouts/__init__.py: -------------------------------------------------------------------------------- 1 | from .qwerty import QWERTY 2 | from .qwertz import QWERTZ 3 | from .azerty import AZERTY 4 | -------------------------------------------------------------------------------- /pico-badusb/boot.py: -------------------------------------------------------------------------------- 1 | from badusb.boot import Boot 2 | 3 | # Loads default device setup 4 | if __name__ == "__main__": 5 | Boot() 6 | -------------------------------------------------------------------------------- /pico-badusb/main.py: -------------------------------------------------------------------------------- 1 | from badusb.command import Command 2 | 3 | # Loads and executes commands from the payload 4 | if __name__ == "__main__": 5 | Command().execute("./payload.txt") 6 | -------------------------------------------------------------------------------- /pico-badusb/payload.txt: -------------------------------------------------------------------------------- 1 | REM This is an example of a payload file 2 | DELAY 1000 3 | LED ON 4 | HOTKEY GUI R 5 | DELAY 500 6 | STRING cmd.exe 7 | PRESS ENTER 8 | DELAY 500 9 | STRING start https://youtu.be/dQw4w9WgXcQ 10 | PRESS ENTER 11 | LED OFF 12 | -------------------------------------------------------------------------------- /pico-badusb/badusb/boot.py: -------------------------------------------------------------------------------- 1 | from board import GP1 2 | from digitalio import DigitalInOut, Pull 3 | from storage import disable_usb_drive 4 | 5 | # Boot handler class 6 | class Boot: 7 | 8 | # Initial setup 9 | def __init__(self) -> None: 10 | gp1 = DigitalInOut(GP1) 11 | gp1.switch_to_input(pull=Pull.UP) 12 | 13 | if not gp1.value: 14 | disable_usb_drive() 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Kacper Bartocha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pico-badusb/badusb/keyboard.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | from usb_hid import Device 3 | from .layouts import QWERTY 4 | 5 | # Keyboard handler class 6 | class Keyboard: 7 | 8 | # ASCII layout 9 | ASCII = QWERTY 10 | 11 | # Keycodes 12 | UP = 0x52 13 | DOWN = 0x51 14 | LEFT = 0x50 15 | RIGHT = 0x4F 16 | PAGEUP = 0x4B 17 | PAGEDOWN = 0x4E 18 | HOME = 0x4A 19 | END = 0x4D 20 | INSERT = 0x49 21 | DELETE = 0x4C 22 | BACKSPACE = 0x2A 23 | TAB = 0x2B 24 | SPACE = 0x2C 25 | ENTER = 0x28 26 | ESCAPE = 0x29 27 | PAUSE = 0x48 28 | PRINTSCREEN = 0x46 29 | MENU = 0x65 30 | F1 = 0x3A 31 | F2 = 0x3B 32 | F3 = 0x3C 33 | F4 = 0x3D 34 | F5 = 0x3E 35 | F6 = 0x3F 36 | F7 = 0x40 37 | F8 = 0x41 38 | F9 = 0x42 39 | F10 = 0x43 40 | F11 = 0x44 41 | F12 = 0x45 42 | SHIFT = 0xE1 43 | ALT = 0xE2 44 | ALTGR = 0xE6 45 | CONTROL = 0xE0 46 | CTRL = CONTROL 47 | GUI = 0xE3 48 | COMMAND = GUI 49 | WINDOWS = GUI 50 | CAPSLOCK = 0x39 51 | NUMLOCK = 0x53 52 | SCROLLOCK = 0x47 53 | 54 | # Initial setup 55 | def __init__(self) -> None: 56 | self.__keyboard = Device.KEYBOARD 57 | self.__report = bytearray(8) 58 | self.__report_modifier = memoryview(self.__report)[0:1] 59 | self.__report_keys = memoryview(self.__report)[2:] 60 | 61 | self.release() 62 | 63 | # Presses up to 6 unique keys 64 | def press(self, *keycodes: int) -> None: 65 | for keycode in keycodes: 66 | if 0xE0 <= keycode <= 0xE7: 67 | self.__report_modifier[0] |= 1 << (keycode - 0xE0) 68 | 69 | else: 70 | report_keys = self.__report_keys 71 | for i in range(6): 72 | report_key = report_keys[i] 73 | 74 | if report_key == 0: 75 | report_keys[i] = keycode 76 | break 77 | 78 | if report_key == keycode: 79 | break 80 | 81 | self.__keyboard.send_report(self.__report) 82 | 83 | # Enters a key combination 84 | def hotkey(self, *keycodes: int) -> None: 85 | self.press(*keycodes) 86 | self.release() 87 | 88 | # Enters an ASCII character string 89 | def string(self, string: str, typespeed: float) -> None: 90 | for char in string: 91 | ordinal = ord(char) 92 | 93 | if ordinal < 0x80: 94 | keycode = self.ASCII[ordinal] 95 | 96 | self.press(*keycode) 97 | self.release() 98 | 99 | sleep(typespeed) 100 | 101 | # Releases all pressed keys 102 | def release(self) -> None: 103 | for i in range(8): 104 | self.__report[i] = 0 105 | 106 | self.__keyboard.send_report(self.__report) 107 | -------------------------------------------------------------------------------- /pico-badusb/badusb/command.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | from board import LED, GP5 3 | from digitalio import DigitalInOut, Direction, Pull 4 | from .keyboard import Keyboard 5 | 6 | # Command handler class 7 | class Command: 8 | 9 | # Initial setup 10 | def __init__(self) -> None: 11 | self.__keyboard = Keyboard() 12 | self.__led = DigitalInOut(LED) 13 | self.__led.direction = Direction.OUTPUT 14 | self.__typespeed = 0.0 15 | self.__delay = 0.5 16 | self.__string = "" 17 | self.__arguments = [] 18 | self.__pause() 19 | 20 | # Pauses the load execution 21 | def __pause(self) -> None: 22 | gp5 = DigitalInOut(GP5) 23 | gp5.switch_to_input(pull=Pull.UP) 24 | 25 | while not gp5.value: 26 | pass 27 | 28 | # Alias to HOTKEY 29 | def press(self) -> None: 30 | self.hotkey() 31 | 32 | # Enters a key combination 33 | def hotkey(self) -> None: 34 | keycodes = [] 35 | 36 | for argument in self.__arguments: 37 | if len(argument) == 1: 38 | ordinal = ord(argument.lower()) 39 | 40 | if ordinal < 0x80: 41 | keycode = self.__keyboard.ASCII[ordinal] 42 | 43 | keycodes.append(*keycode) 44 | 45 | elif hasattr(Keyboard, argument.upper()): 46 | keycodes.append(getattr(Keyboard, argument.upper())) 47 | 48 | self.__keyboard.hotkey(*keycodes) 49 | 50 | # Enters a string of ASCII characters 51 | def string(self) -> None: 52 | self.__keyboard.string(self.__string, self.__typespeed ) 53 | 54 | # Sets the type speed of strings 55 | def typespeed(self) -> None: 56 | if len(self.__arguments) > 0: 57 | self.__typespeed = int(self.__arguments[0]) / 1000 58 | 59 | # Sets the delay between commands 60 | def delay(self) -> None: 61 | if len(self.__arguments) > 0: 62 | time = int(self.__arguments[0]) / 1000 63 | 64 | else: 65 | time = self.__delay 66 | 67 | sleep(time) 68 | 69 | # Turns on/off the onboard LED diode 70 | def led(self) -> None: 71 | if len(self.__arguments) > 0: 72 | if self.__arguments[0].lower() == "on": 73 | self.__led.value = True 74 | 75 | else: 76 | self.__led.value = False 77 | 78 | # Executes instructions and validates them 79 | def execute(self, path: str) -> None: 80 | with open(path, "r", encoding="utf-8") as payload: 81 | for string in payload.readlines(): 82 | self.__string = string.replace("\n", "").replace("\r", "") 83 | self.__arguments = self.__string.split(" ") 84 | 85 | if len(self.__arguments) > 0: 86 | command = self.__arguments.pop(0).lower() 87 | 88 | if hasattr(Command, command): 89 | self.__string = self.__string[len(command) + 1:] 90 | 91 | try: 92 | getattr(Command, command)(self) 93 | 94 | except Exception as e: 95 | self.__keyboard.release() 96 | -------------------------------------------------------------------------------- /pico-badusb/badusb/layouts/azerty.py: -------------------------------------------------------------------------------- 1 | AZERTY = ( 2 | [0x00], # NUL 3 | [0x00], # SOH 4 | [0x00], # STX 5 | [0x00], # ETX 6 | [0x00], # EOT 7 | [0x00], # ENQ 8 | [0x00], # ACK 9 | [0x00], # BEL 10 | [0x2A], # BS 11 | [0x2B], # TAB 12 | [0x28], # LF 13 | [0x00], # VT 14 | [0x00], # FF 15 | [0x00], # CR 16 | [0x00], # SO 17 | [0x00], # SI 18 | [0x00], # DLE 19 | [0x00], # DC1 20 | [0x00], # DC2 21 | [0x00], # DC3 22 | [0x00], # DC4 23 | [0x00], # NAK 24 | [0x00], # SYN 25 | [0x00], # ETB 26 | [0x00], # CAN 27 | [0x00], # EM 28 | [0x00], # SUB 29 | [0x29], # ESC 30 | [0x00], # FS 31 | [0x00], # GS 32 | [0x00], # RS 33 | [0x00], # US 34 | [0x2C], # SPACE 35 | [0x38], # ! 36 | [0x20], # " 37 | [0xE6, 0x20], # # 38 | [0x30], # $ 39 | [0xE1, 0x34], # % 40 | [0x1E], # & 41 | [0x21], # ' 42 | [0x22], # ( 43 | [0x2D], # ) 44 | [0x31], # * 45 | [0xE1, 0x2E], # + 46 | [0x10], # , 47 | [0x23], # - 48 | [0xE1, 0x36], # . 49 | [0xE1, 0x37], # / 50 | [0xE1, 0x27], # 0 51 | [0xE1, 0x1E], # 1 52 | [0xE1, 0x1F], # 2 53 | [0xE1, 0x20], # 3 54 | [0xE1, 0x21], # 4 55 | [0xE1, 0x22], # 5 56 | [0xE1, 0x23], # 6 57 | [0xE1, 0x24], # 7 58 | [0xE1, 0x25], # 8 59 | [0xE1, 0x26], # 9 60 | [0x37], # : 61 | [0x36], # ; 62 | [0x64], # < 63 | [0x2E], # = 64 | [0xE1, 0x64], # > 65 | [0xE1, 0x10], # ? 66 | [0xE6, 0x27], # @ 67 | [0xE1, 0x14], # A 68 | [0xE1, 0x05], # B 69 | [0xE1, 0x06], # C 70 | [0xE1, 0x07], # D 71 | [0xE1, 0x08], # E 72 | [0xE1, 0x09], # F 73 | [0xE1, 0x0A], # G 74 | [0xE1, 0x0B], # H 75 | [0xE1, 0x0C], # I 76 | [0xE1, 0x0D], # J 77 | [0xE1, 0x0E], # K 78 | [0xE1, 0x0F], # L 79 | [0xE1, 0x33], # M 80 | [0xE1, 0x11], # N 81 | [0xE1, 0x12], # O 82 | [0xE1, 0x13], # P 83 | [0xE1, 0x04], # Q 84 | [0xE1, 0x15], # R 85 | [0xE1, 0x16], # S 86 | [0xE1, 0x17], # T 87 | [0xE1, 0x18], # U 88 | [0xE1, 0x19], # V 89 | [0xE1, 0x1D], # W 90 | [0xE1, 0x1B], # X 91 | [0xE1, 0x1C], # Y 92 | [0xE1, 0x1A], # Z 93 | [0xE6, 0x22], # [ 94 | [0xE6, 0x25], # \ 95 | [0xE6, 0x2D], # ] 96 | [0xE6, 0x26], # ^ 97 | [0x25], # _ 98 | [0xE6, 0x24], # ` 99 | [0x14], # a 100 | [0x05], # b 101 | [0x06], # c 102 | [0x07], # d 103 | [0x08], # e 104 | [0x09], # f 105 | [0x0A], # g 106 | [0x0B], # h 107 | [0x0C], # i 108 | [0x0D], # j 109 | [0x0E], # k 110 | [0x0F], # l 111 | [0x33], # m 112 | [0x11], # n 113 | [0x12], # o 114 | [0x13], # p 115 | [0x04], # q 116 | [0x15], # r 117 | [0x16], # s 118 | [0x17], # t 119 | [0x18], # u 120 | [0x19], # v 121 | [0x1D], # w 122 | [0x1B], # x 123 | [0x1C], # y 124 | [0x1A], # z 125 | [0xE6, 0x21], # { 126 | [0xE6, 0x23], # | 127 | [0xE6, 0x2E], # } 128 | [0xE6, 0x1F], # ~ 129 | [0x4C], # DEL 130 | ) 131 | -------------------------------------------------------------------------------- /pico-badusb/badusb/layouts/qwerty.py: -------------------------------------------------------------------------------- 1 | QWERTY = ( 2 | [0x00], # NUL 3 | [0x00], # SOH 4 | [0x00], # STX 5 | [0x00], # ETX 6 | [0x00], # EOT 7 | [0x00], # ENQ 8 | [0x00], # ACK 9 | [0x00], # BEL 10 | [0x2A], # BS 11 | [0x2B], # TAB 12 | [0x28], # LF 13 | [0x00], # VT 14 | [0x00], # FF 15 | [0x00], # CR 16 | [0x00], # SO 17 | [0x00], # SI 18 | [0x00], # DLE 19 | [0x00], # DC1 20 | [0x00], # DC2 21 | [0x00], # DC3 22 | [0x00], # DC4 23 | [0x00], # NAK 24 | [0x00], # SYN 25 | [0x00], # ETB 26 | [0x00], # CAN 27 | [0x00], # EM 28 | [0x00], # SUB 29 | [0x29], # ESC 30 | [0x00], # FS 31 | [0x00], # GS 32 | [0x00], # RS 33 | [0x00], # US 34 | [0x2C], # SPACE 35 | [0xE1, 0x1E], # ! 36 | [0xE1, 0x34], # " 37 | [0xE1, 0x20], # # 38 | [0xE1, 0x21], # $ 39 | [0xE1, 0x22], # % 40 | [0xE1, 0x24], # & 41 | [0x34], # ' 42 | [0xE1, 0x26], # ( 43 | [0xE1, 0x27], # ) 44 | [0xE1, 0x25], # * 45 | [0xE1, 0x2E], # + 46 | [0x36], # , 47 | [0x2D], # - 48 | [0x37], # . 49 | [0x38], # / 50 | [0x27], # 0 51 | [0x1E], # 1 52 | [0x1F], # 2 53 | [0x20], # 3 54 | [0x21], # 4 55 | [0x22], # 5 56 | [0x23], # 6 57 | [0x24], # 7 58 | [0x25], # 8 59 | [0x26], # 9 60 | [0xE1, 0x33], # : 61 | [0x33], # ; 62 | [0xE1, 0x36], # < 63 | [0x2E], # = 64 | [0xE1, 0x37], # > 65 | [0xE1, 0x38], # ? 66 | [0xE1, 0x1F], # @ 67 | [0xE1, 0x04], # A 68 | [0xE1, 0x05], # B 69 | [0xE1, 0x06], # C 70 | [0xE1, 0x07], # D 71 | [0xE1, 0x08], # E 72 | [0xE1, 0x09], # F 73 | [0xE1, 0x0A], # G 74 | [0xE1, 0x0B], # H 75 | [0xE1, 0x0C], # I 76 | [0xE1, 0x0D], # J 77 | [0xE1, 0x0E], # K 78 | [0xE1, 0x0F], # L 79 | [0xE1, 0x10], # M 80 | [0xE1, 0x11], # N 81 | [0xE1, 0x12], # O 82 | [0xE1, 0x13], # P 83 | [0xE1, 0x14], # Q 84 | [0xE1, 0x15], # R 85 | [0xE1, 0x16], # S 86 | [0xE1, 0x17], # T 87 | [0xE1, 0x18], # U 88 | [0xE1, 0x19], # V 89 | [0xE1, 0x1A], # W 90 | [0xE1, 0x1B], # X 91 | [0xE1, 0x1C], # Y 92 | [0xE1, 0x1D], # Z 93 | [0x2F], # [ 94 | [0x31], # \ 95 | [0x30], # ] 96 | [0xE1, 0x23], # ^ 97 | [0xE1, 0x2D], # _ 98 | [0x35], # ` 99 | [0x04], # a 100 | [0x05], # b 101 | [0x06], # c 102 | [0x07], # d 103 | [0x08], # e 104 | [0x09], # f 105 | [0x0A], # g 106 | [0x0B], # h 107 | [0x0C], # i 108 | [0x0D], # j 109 | [0x0E], # k 110 | [0x0F], # l 111 | [0x10], # m 112 | [0x11], # n 113 | [0x12], # o 114 | [0x13], # p 115 | [0x14], # q 116 | [0x15], # r 117 | [0x16], # s 118 | [0x17], # t 119 | [0x18], # u 120 | [0x19], # v 121 | [0x1A], # w 122 | [0x1B], # x 123 | [0x1C], # y 124 | [0x1D], # z 125 | [0xE1, 0x2F], # { 126 | [0xE1, 0x31], # | 127 | [0xE1, 0x30], # } 128 | [0xE1, 0x35], # ~ 129 | [0x4C], # DEL 130 | ) 131 | -------------------------------------------------------------------------------- /pico-badusb/badusb/layouts/qwertz.py: -------------------------------------------------------------------------------- 1 | QWERTZ = ( 2 | [0x00], # NUL 3 | [0x00], # SOH 4 | [0x00], # STX 5 | [0x00], # ETX 6 | [0x00], # EOT 7 | [0x00], # ENQ 8 | [0x00], # ACK 9 | [0x00], # BEL 10 | [0x2A], # BS 11 | [0x2B], # TAB 12 | [0x28], # LF 13 | [0x00], # VT 14 | [0x00], # FF 15 | [0x00], # CR 16 | [0x00], # SO 17 | [0x00], # SI 18 | [0x00], # DLE 19 | [0x00], # DC1 20 | [0x00], # DC2 21 | [0x00], # DC3 22 | [0x00], # DC4 23 | [0x00], # NAK 24 | [0x00], # SYN 25 | [0x00], # ETB 26 | [0x00], # CAN 27 | [0x00], # EM 28 | [0x00], # SUB 29 | [0x29], # ESC 30 | [0x00], # FS 31 | [0x00], # GS 32 | [0x00], # RS 33 | [0x00], # US 34 | [0x2C], # SPACE 35 | [0xE1, 0x1E], # ! 36 | [0xE1, 0x1F], # " 37 | [0x31], # # 38 | [0xE1, 0x21], # $ 39 | [0xE1, 0x22], # % 40 | [0xE1, 0x23], # & 41 | [0xE1, 0x31], # ' 42 | [0xE1, 0x25], # ( 43 | [0xE1, 0x26], # ) 44 | [0xE1, 0x30], # * 45 | [0x30], # + 46 | [0x36], # , 47 | [0x38], # - 48 | [0x37], # . 49 | [0xE1, 0x24], # / 50 | [0x27], # 0 51 | [0x1E], # 1 52 | [0x1F], # 2 53 | [0x20], # 3 54 | [0x21], # 4 55 | [0x22], # 5 56 | [0x23], # 6 57 | [0x24], # 7 58 | [0x25], # 8 59 | [0x26], # 9 60 | [0xE1, 0x37], # : 61 | [0xE1, 0x36], # ; 62 | [0x64], # < 63 | [0xE1, 0x27], # = 64 | [0xE1, 0x64], # > 65 | [0xE1, 0x2D], # ? 66 | [0xE6, 0x14], # @ 67 | [0xE1, 0x04], # A 68 | [0xE1, 0x05], # B 69 | [0xE1, 0x06], # C 70 | [0xE1, 0x07], # D 71 | [0xE1, 0x08], # E 72 | [0xE1, 0x09], # F 73 | [0xE1, 0x0A], # G 74 | [0xE1, 0x0B], # H 75 | [0xE1, 0x0C], # I 76 | [0xE1, 0x0D], # J 77 | [0xE1, 0x0E], # K 78 | [0xE1, 0x0F], # L 79 | [0xE1, 0x10], # M 80 | [0xE1, 0x11], # N 81 | [0xE1, 0x12], # O 82 | [0xE1, 0x13], # P 83 | [0xE1, 0x14], # Q 84 | [0xE1, 0x15], # R 85 | [0xE1, 0x16], # S 86 | [0xE1, 0x17], # T 87 | [0xE1, 0x18], # U 88 | [0xE1, 0x19], # V 89 | [0xE1, 0x1A], # W 90 | [0xE1, 0x1B], # X 91 | [0xE1, 0x1D], # Y 92 | [0xE1, 0x1C], # Z 93 | [0xE6, 0x25], # [ 94 | [0xE6, 0x2D], # \ 95 | [0xE6, 0x26], # ] 96 | [0x35], # ^ 97 | [0xE1, 0x38], # _ 98 | [0xE1, 0x2E], # ` 99 | [0x04], # a 100 | [0x05], # b 101 | [0x06], # c 102 | [0x07], # d 103 | [0x08], # e 104 | [0x09], # f 105 | [0x0A], # g 106 | [0x0B], # h 107 | [0x0C], # i 108 | [0x0D], # j 109 | [0x0E], # k 110 | [0x0F], # l 111 | [0x10], # m 112 | [0x11], # n 113 | [0x12], # o 114 | [0x13], # p 115 | [0x14], # q 116 | [0x15], # r 117 | [0x16], # s 118 | [0x17], # t 119 | [0x18], # u 120 | [0x19], # v 121 | [0x1A], # w 122 | [0x1B], # x 123 | [0x1D], # y 124 | [0x1C], # z 125 | [0xE6, 0x24], # { 126 | [0xE6, 0x64], # | 127 | [0xE6, 0x27], # } 128 | [0xE6, 0x30], # ~ 129 | [0x4C], # DEL 130 | ) 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raspberry Pi Pico BadUSB 2 | Pico BadUSB is a simple implementation of the [BadUSB](https://en.wikipedia.org/wiki/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](https://github.com/kacperbartocha/pico-badusb#setup). Additionally, it uses a similar syntax as [DuckyScript](https://docs.hak5.org/hak5-usb-rubber-ducky/duckyscript-tm-quick-reference), so writing the payload will be more intuitive for experienced Rubber Ducky users. 3 | 4 | If you want to learn more about the Raspberry Pi Pico, refer to the [documentation](https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-python-sdk.pdf) or visit the [website](https://projects.raspberrypi.org/en/projects/getting-started-with-the-pico). 5 | 6 | ## Overview 7 | 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```. 8 | 9 | ## Setup 10 | 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. 11 | 12 | If the board has been used before, it may be necessary to [reset](https://github.com/kacperbartocha/pico-badusb#reset-flash) the device's Flash memory. 13 | 14 | ### Installation steps 15 | 0. [Reset Flash](https://github.com/kacperbartocha/pico-badusb#reset-flash) memory if you have used the device before 16 | 1. Hold down the ```BOOTSEL``` button while plugging in the ```micro USB``` cable 17 | 2. Drag and drop the file ```pico-badusb.uf2``` onto the media 18 | 3. Wait for the drive to remount with the following files: 19 | * ```boot.py``` 20 | * ```boot_out.txt``` 21 | * ```main.py``` 22 | * ```payload.txt``` 23 | * ```license.txt``` 24 | 25 | If you encounter a problem or if the selected ```uf2``` file doesn't work, the source code is available in the [pico-badusb directory](https://github.com/kacperbartocha/pico-badusb/tree/main/pico-badusb). To run the program, prepare the board using [Thonny IDE](https://thonny.org) 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. 26 | 27 | ### UF2 files 28 | 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. 29 | 30 | | Board | Layout | File | MD5 | 31 | |:-------|:-------------|:----------------------------------------------------------------------------------------------------------------------------|:---------------------------------------| 32 | | Pico | ```QWERTY``` | [pico-badusb.uf2](https://github.com/kacperbartocha/pico-badusb/releases/download/v2.0.0/pico-badusb.uf2) | ```78bd80bac2f451fd87a586460f52350c``` | 33 | | Pico W | ```QWERTY``` | [pico-badusb-w.uf2](https://github.com/kacperbartocha/pico-badusb/releases/download/v2.0.0/pico-badusb-w.uf2) | ```e53cef1f5bb97ca39ab976239854ada4``` | 34 | | Pico 2 | ```QWERTY``` | [pico-badusb-2.uf2](https://github.com/kacperbartocha/pico-badusb/releases/download/v2.0.0/pico-badusb-2.uf2) | ```a8b9f56ab1c26579a7f5551b57accdbe``` | 35 | | Pico | ```QWERTZ``` | [pico-badusb-qwertz.uf2](https://github.com/kacperbartocha/pico-badusb/releases/download/v2.0.0/pico-badusb-qwertz.uf2) | ```662ccbcb6c9eab3b41ba6fa43aac6bd9``` | 36 | | Pico W | ```QWERTZ``` | [pico-badusb-w-qwertz.uf2](https://github.com/kacperbartocha/pico-badusb/releases/download/v2.0.0/pico-badusb-w-qwertz.uf2) | ```2f4a04d8c68941d56648ab97785c09c2``` | 37 | | Pico 2 | ```QWERTZ``` | [pico-badusb-2-qwertz.uf2](https://github.com/kacperbartocha/pico-badusb/releases/download/v2.0.0/pico-badusb-2-qwertz.uf2) | ```06263d2c851b2064a6e51800b1b4ab1a``` | 38 | | Pico | ```AZERTY``` | [pico-badusb-azerty.uf2](https://github.com/kacperbartocha/pico-badusb/releases/download/v2.0.0/pico-badusb-azerty.uf2) | ```bca8af6048141ccb382e4824c4049ec8``` | 39 | | Pico W | ```AZERTY``` | [pico-badusb-w-azerty.uf2](https://github.com/kacperbartocha/pico-badusb/releases/download/v2.0.0/pico-badusb-w-azerty.uf2) | ```99e63c5cd282ca5c87080b8d2f6e3748``` | 40 | | Pico 2 | ```AZERTY``` | [pico-badusb-2-azerty.uf2](https://github.com/kacperbartocha/pico-badusb/releases/download/v2.0.0/pico-badusb-2-azerty.uf2) | ```aafad906286b0210efab990281b2deb5``` | 41 | 42 | ### Reset Flash 43 | 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](https://datasheets.raspberrypi.com/soft/flash_nuke.uf2). If you don't see mass memory, make sure you removed the jumper link between pin ```GP1``` and ```GND```. 44 | 45 | ## Manual 46 | 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](https://github.com/kacperbartocha/pico-badusb#development). 47 | 48 | ### Commands 49 | 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](https://github.com/kacperbartocha/pico-badusb#commands) and [keycodes](https://github.com/kacperbartocha/pico-badusb#keycodes) can be written with any combination of lowercase and uppercase letters. 50 | 51 | | Command | Description | Example | 52 | |:----------|:------------------------------------|:------------------------------| 53 | | REM | Adds a comment | ```REM This is a comment``` | 54 | | DELAY | Adds a delay | ```DELAY 500``` | 55 | | TYPESPEED | Changes the typing speed | ```TYPESPEED 100``` | 56 | | PRESS | Alias to ```HOTKEY``` command | ```PRESS ENTER``` | 57 | | HOTKEY | Enters key combination | ```HOTKEY GUI R``` | 58 | | STRING | Enters a string of ASCII characters | ```STRING This is a string``` | 59 | | LED | Turns on/off the onboard diode | ```LED ON ``` | 60 | 61 | ##### REM 62 | 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. 63 | 64 | ##### DELAY 65 | 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. 66 | 67 | ##### TYPESPEED 68 | ```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. 69 | 70 | ##### PRESS 71 | 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. 72 | 73 | ##### HOTKEY 74 | 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. 75 | 76 | ##### STRING 77 | 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. 78 | 79 | ##### LED 80 | 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. 81 | 82 | ### Keycodes 83 | 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. 84 | 85 | #### Cursor Keys 86 | ```UP``` ```DOWN``` ```LEFT``` ```RIGHT```\ 87 | ```PAGEUP``` ```PAGEDOWN``` ```HOME``` ```END```\ 88 | ```INSERT``` ```DELETE``` ```BACKSPACE```\ 89 | ```SPACE``` ```TAB``` 90 | 91 | #### System Keys 92 | ```ENTER``` ```ESCAPE``` ```PAUSE``` ```PRINTSCREEN``` ```MENU```\ 93 | ```F1``` ```F2``` ```F3``` ```F4``` ```F5``` ```F6``` ```F7```\ 94 | ```F8``` ```F9``` ```F10``` ```F11``` ```F12``` 95 | 96 | #### Modifier Keys 97 | ```SHIFT``` ```CONTROL``` ```CTRL``` ```ALT```\ 98 | ```ALTGR``` ```GUI``` ```COMMAND``` ```WINDOWS``` 99 | 100 | #### Lock Keys 101 | ```CAPSLOCK``` ```NUMLOCK``` ```SCROLLOCK``` 102 | 103 | ### Example 104 | The following example demonstrates the full functionality of Pico BadUSB. First, it activates the built-in LED, then, using [Windows](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/windows-commands) features, we open the defined link in the default browser. Finally, the LED turns off. 105 | 106 | ```text 107 | REM This is an example of a payload file 108 | DELAY 1000 109 | LED ON 110 | HOTKEY GUI R 111 | DELAY 500 112 | STRING cmd.exe 113 | PRESS ENTER 114 | DELAY 500 115 | STRING start https://youtu.be/dQw4w9WgXcQ 116 | PRESS ENTER 117 | LED OFF 118 | ``` 119 | 120 | ## Other features 121 | 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. 122 | 123 | ### Storage 124 | 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](https://datasheets.raspberrypi.com/pico/Pico-R3-A4-Pinout.pdf). 125 | 126 | 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. 127 | 128 | ```python 129 | from badusb.boot import Boot 130 | 131 | # You can omit the if-else statement 132 | if __name__ == "__main__": 133 | Boot() 134 | ``` 135 | 136 | ### Development 137 | 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](https://datasheets.raspberrypi.com/pico/Pico-R3-A4-Pinout.pdf). 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. 138 | 139 | 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. 140 | 141 | ### Layout 142 | 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. 143 | 144 | ## References 145 | \[1\] [Raspberry Pi Ltd. (2024). Raspberry Pi Pico Python SDK](https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-python-sdk.pdf)\ 146 | \[2\] [Raspberry Pi Ltd. (2024). Getting started with Raspberry Pi Pico](https://projects.raspberrypi.org/en/projects/getting-started-with-the-pico)\ 147 | \[3\] [Raspberry Pi Ltd. (2024). Raspberry Pi Pico Pinout](https://datasheets.raspberrypi.com/pico/Pico-R3-A4-Pinout.pdf)\ 148 | \[4\] [MicroPython & CircuitPython contributors. (2024). Adafruit CircuitPython](https://docs.circuitpython.org)\ 149 | \[5\] [Scott Shawcroft. (2024). Adafruit HID library](https://docs.circuitpython.org/projects/hid) 150 | --------------------------------------------------------------------------------