Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
Pi-Zero-2W-Bad-USB — Configure your Pi Zero 2W to be a BadUSB | Kitploit
Tools/GitHubGitHub/psycostea/pi-zero-2w-bad-usb
Embedded Systems SecurityExploitationScripting & AutomationHardware HackingCTFPenetration TestingLearning & EducationRed TeamingPayload Development
GitHubpsycostea/pi-zero-2w-bad-usb

Pi-Zero-2W-Bad-USB

Configure your Pi Zero 2W to be a BadUSB

372344 months agoReviewed by Kitploit

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
View Repository

Raspberry Pi Zero 2 W BadUSB HID Toolkit

A programmable BadUSB / HID attack platform built on a Raspberry Pi Zero 2 W. The Pi enumerates as a USB composite device (keyboard plus an optional read-only mass-storage volume) and executes Ducky-Script-style payloads against the host it's plugged into. Designed for authorised red-team engagements, penetration tests, and CTFs.

⚠️ Legal notice. Use only on systems you own or have explicit written permission to test. Unauthorised access is illegal in most jurisdictions, and pretending you didn't know won't help.


Table of contents

  1. Features
  2. How it works
  3. Hardware
  4. Install
  5. Daily operation
  6. Writing payloads
  7. Configuration reference
  8. Architecture notes
  9. Tests
  10. Troubleshooting
  11. Repository layout
  12. Credits

Features

  • Programmable keystroke payloads in a Ducky-Script-compatible dialect.
  • Reliable host-attach detection via the UDC configured state — no spurious payload fires at boot.
  • "Reset between attacks" that actually works on Pi Zero 2 W hardware. Unplug, replug, fire again — no power-cycle.
  • Configurable safeguards against runaway loops if the device is left plugged in: per-fire minimum interval and a fires-per-minute rate limit, both env-var overrideable.
  • Optional composite mass-storage gadget backed by a flat image file (read-only by default — exposing your live SD card was the old hard-to-debug FS-corruption foot-gun).
  • US and UK keyboard layouts selectable per payload with LAYOUT.
  • Variables, IF / ELSE, WHILE, HOLD / RELEASE, INJECT_MOD, RANDOM_* generators, STRING_BLOCK / STRINGLN_BLOCK, DEFINE.
  • systemd integration with ExecStop that tears the gadget down cleanly. No leftover configfs state, restart works without rebooting.
  • udev-managed permissions for /dev/hidg0 — no world-writable device nodes.
  • 34-test pytest suite for the Ducky parser, runnable on any host with no Pi attached.
  • ACT LED status indicator after each payload run.

How it works

+----------------+        USB cable        +-------------+
|  Raspberry Pi  | ===================>>>  |  Host PC    |
|  Zero 2 W      |   (Pi emulates HID +    |  (target)   |
|  (this device) |    optional drive)      |             |
+----------------+                         +-------------+
        |
        |  /home/pi/pi-badusb/
        |
        +-- badusb.service ----> monitor_and_run.py
                                   |
                                   |  on `state == configured`:
                                   v
                                 run_payload.py
                                   |
                                   v
                                 /dev/hidg0  (USB HID gadget)
  1. At boot, the badusb.service systemd unit runs gadget_setup.sh, which uses configfs/libcomposite to compose a USB gadget with an HID keyboard function and (optionally) a mass-storage LUN backed by a flat image file at /var/badusb/storage.img.
  2. The unit then runs monitor_and_run.py. It polls /sys/class/udc/<udc>/state and waits for configured — the USB-spec state that means a host has successfully enumerated the gadget. (We do not use /dev/hidg0's existence as a signal: that's true the moment the gadget binds to the UDC at boot, regardless of whether anything is plugged in.)
  3. When the host attaches, the listener executes run_payload.py, which parses payload.txt and writes HID reports to /dev/hidg0.
  4. When the payload finishes, the listener actively unbinds the gadget from the UDC (the Pi Zero 2 W cannot detect physical disconnect via software — see Architecture notes), sleeps a cooldown, and rebinds. The device then waits for the next configured transition.

Hardware

ComponentNote
Raspberry Pi Zero 2 WTested on 2026-05 hardware revision. Older Pi Zero W with the BCM2835 dwc_otg driver also works in principle, but this README assumes 2 W with dwc2.
micro-USB to USB-A cableOr a "USB stick" form-factor adapter that lets the Pi plug straight into a host port.
Optional: separate chargerIf you want to power the Pi from a non-host source so the listener can boot before being plugged into a target (otherwise the host port supplies the power).

The Pi Zero 2 W has two micro-USB ports:

  • PWR IN — power only, doesn't expose USB data lines to the dwc2 OTG block.
  • USB — the OTG data port; this is where you plug into the target.

Software

RequirementWhy
Raspberry Pi OS (Debian Bookworm or Trixie, 64-bit Lite recommended)The install script writes to /boot/firmware/... on Bookworm+ and falls back to /boot/... on older images.
Python 3Comes with Pi OS.
mkfs.vfatFor formatting the mass-storage backing image on first run. Skip if you disable mass storage.
Root access for setupTouches systemd, udev, and /boot/firmware/config.txt.

Install

Clone or copy the repo into the Pi, then run the installer:

git clone http://your-gitea/admin/Pi-Zero-2W-Bad-USB.git /home/pi/pi-badusb
cd /home/pi/pi-badusb
sudo ./install.sh
sudo reboot

After reboot, enable and start the service:

sudo systemctl enable --now badusb.service
journalctl -u badusb -f

install.sh is idempotent — re-run it whenever you change project files. It:

  • Detects /boot/firmware (Bookworm+) vs /boot (older).
  • Ensures dtoverlay=dwc2,dr_mode=otg is active under an [all] block in config.txt. Raspberry Pi Imager defaults put this line inside a [cm5] filter that doesn't apply on Pi Zero 2 W; the installer appends a sentinel-marked override so re-runs don't duplicate it.
  • Ensures modules-load=dwc2 is in cmdline.txt.
  • Warns if g_ether is still present in cmdline.txt (it steals the UDC from libcomposite and breaks gadget mode).
  • Installs the systemd unit at /etc/systemd/system/badusb.service.
  • Installs the udev rule at /etc/udev/rules.d/99-badusb-hidg.rules so /dev/hidg0 is group-writable by plugdev.
  • Adds the pi user to plugdev.
  • Creates /var/badusb/ for the mass-storage backing image.

Daily operation

# Start / stop / restart
sudo systemctl start badusb
sudo systemctl stop badusb
sudo systemctl restart badusb              # safe to do while plugged in

# Watch live
journalctl -u badusb -f

# Disable autostart on boot
sudo systemctl disable badusb

# Tune timings (creates an override drop-in)
sudo systemctl edit badusb
# (paste an [Service] block with Environment="BADUSB_REARM_COOLDOWN_S=8" etc)
sudo systemctl restart badusb

The service depends on sys-kernel-config.mount and the presence of a UDC, so it can't fire payloads before the gadget is actually ready.

Editing the payload doesn't require a restart — payload.txt is read fresh on every plug-in.


Writing payloads

payload.txt lives in the install directory. The full command reference is in payload_commands.md.

Minimal example

REM Open Run dialog and type a greeting via Notepad
LAYOUT US
GUI r
DELAY 1500
STRING notepad
ENTER
DELAY 2500
STRINGLN Hello from the Pi Zero 2 W

Variables, conditionals, loops

VAR $USER="alice"
VAR $COUNT=0
WHILE $COUNT < 3
  STRINGLN Hello $USER (iteration $COUNT)
  VAR $COUNT = $COUNT + 1
END_WHILE

IF $USER == "alice"
  STRINGLN matched
ELSE
  STRINGLN missed
END_IF
Download Tool