Ducky Script · Volume 3

Ducky Script Volume 3 — The Language Core

Ducky Script 1.0 — the foundation every device and every payload is built on: syntax, STRING, DELAY, REM, key names, and modifiers

Contents

SectionTopic
1About this volume
2The shape of a payload
3REM — comments
4STRING and STRINGLN — typing text
5DELAY — the most important command
6Named keys — the key catalogue
7Modifier keys and combinations
8The classic payload patterns
9Why 1.0 payloads break — typing blind
10Resources

1. About this volume

This volume is the language core — Ducky Script 1.0, the 2010 macro language. Everything in Vol 4 (the 3.0 language) is built on top of this, and 1.0 is a clean subset of 3.0, so a 1.0 payload runs unmodified on every device in the family. If you learn one volume of language syntax, learn this one — it is the part you will use in 90% of payloads regardless of device.

The 1.0 language is small enough to cover completely. By the end of this volume you will have seen every command 1.0 has.


2. The shape of a payload

A Ducky Script payload is a plain text file, one command per line, processed top to bottom, exactly once, with no branching. A line is a command word (uppercase by convention and, for most, by requirement) optionally followed by an argument.

   Anatomy of a payload line
   ════════════════════════════════════════════════

   STRING    Hello, World!
   ▲         ▲
   │         └── argument (everything after the first space)
   └──────────── command word (uppercase)

   DELAY     500
   ▲         ▲
   │         └── argument (here: milliseconds)
   └──────────── command word

   ENTER

   └──────────── command word with no argument

Rules that trip people up:

  • One command per line. There is no statement separator; the newline is the separator.
  • Command words are uppercase. STRING works; string does not.
  • The argument is literal. After STRING , everything to the end of the line is typed verbatim — including spaces, including what looks like it could be another command. STRING ENTER types the five characters E-N-T-E-R; it does not press Return.
  • Blank lines are ignored. Use them to group a payload visually.
  • There is no “run” concept beyond connection. On a USB Rubber Ducky, the payload runs when the device is plugged in (or the button is pressed — Vol 8). The payload is the program; there is no main().

3. REM — comments

REM (from “remark”) is a comment. The line is ignored by the encoder; it injects nothing.

REM ── Payload: open Notepad on Windows ──
REM Author: tjscientist   Target: Win10/11, US layout
REM Authorization: <engagement ref>   ← put this on EVERY payload
DELAY 1000
GUI r

Two disciplines this manual insists on:

  1. Header every payload with REM lines stating what it does, the target OS and keyboard layout, and the authorization context (Vol 16). A payload with no authorization line is a payload you should not run.
  2. REM your DELAYs. A bare DELAY 2000 is a mystery in six months; REM wait for the Run dialog to focus / DELAY 2000 is maintainable.

Ducky Script 3.0 adds REM_BLOCKEND_REM for multi-line comments — covered in Vol 4, but mentioned here so you recognise it in modern payloads.


4. STRING and STRINGLN — typing text

STRING is the workhorse. It types its argument as keystrokes, automatically handling shift for uppercase letters and shifted symbols — you write STRING Hello! and the device presses SHIFT+H, e, l, l, o, SHIFT+1.

STRING powershell -NoProfile -ExecutionPolicy Bypass

STRINGLN is STRING followed by an automatic ENTER — type the text and submit it. It is the natural command for “type a command and run it”:

STRINGLN whoami            REM types 'whoami' and presses Enter

Ducky Script 3.0 adds the multi-line block forms — STRINGEND_STRING and STRINGLNEND_STRINGLN — for typing whole blocks of text (a script, a config file) without one STRING per line. Those are a 3.0 feature; Vol 4 covers them. In pure 1.0, every typed line is its own STRING/STRINGLN.

The layout caveat, stated once and expanded in Vol 7: STRING types scan codes, and what character a scan code produces depends on the target’s keyboard layout, not yours. STRING ] on a payload encoded for US-QWERTY will produce a different character on an AZERTY target. This is the single biggest cause of “my payload typed garbage” — Vol 7 is the whole volume on it.


5. DELAY — the most important command

DELAY pauses execution for a number of milliseconds. It is, in a blind language, the most important command there is — because a 1.0 payload cannot see the screen, DELAY is the only tool it has to stay synchronised with the target.

DELAY 1000     REM wait one second
DELAY 200      REM wait 200 ms

The minimum effective delay is around 20 ms (Ducky Script 3.0 documents 20 ms as the floor; below that the host may not register the timing). Practical DELAY discipline:

SituationTypical DELAYWhy
After the device is plugged in, before anything500–3000 msthe OS needs time to enumerate the “keyboard” and load its driver
After opening the Run dialog / a launcher200–800 msthe window needs focus before it will accept text
After launching an application1000–5000 msthe app must be up and focused
Between keystrokes in a fragile sequence50–100 ms (or jitter — Vol 5)some targets drop keystrokes typed faster than they can process
Waiting on the network (a download)seconds, generouslyyou are guessing; a 1.0 payload cannot confirm
   The DELAY tax — a 1.0 payload's reliability cost
   ════════════════════════════════════════════════════════

   too short ──► payload races ahead of the target:
                 keystrokes land in the wrong window,
                 commands run before the shell is ready,
                 the payload "doesn't work" intermittently

   too long  ──► payload is slow; the operator's window of
                 physical access is wasted; on a shoulder-
                 surf-risk target, every extra second is risk

   just right ─► you guessed correctly for THIS machine.
                 the next machine may be slower. this is the
                 fundamental fragility of blind injection.

The 3.0 language’s OS/host-state detection (Vol 5) exists precisely to replace guessed DELAYs with confirmed waits — but on 1.0, and in 1.0-style payloads, DELAY discipline is payload reliability.


6. Named keys — the key catalogue

Keys that are not printable characters get named commands. Pressing a named key is one line. The full 1.0/3.0 catalogue:

Cursor and navigation

UP / DOWN / LEFT / RIGHT          (also UPARROW / DOWNARROW / LEFTARROW / RIGHTARROW)
PAGEUP / PAGEDOWN
HOME / END
INSERT
DELETE / DEL
BACKSPACE
TAB
SPACE

System and editing keys

ENTER
ESCAPE
PAUSE / BREAK
PRINTSCREEN
MENU / APP            (the context-menu key)
F1 … F12

Lock keys

CAPSLOCK
NUMLOCK
SCROLLLOCK

A named key can be combined with a STRING argument on some — but the clean mental model is: named keys are their own lines. ENTER on its own line presses Return. TAB on its own line presses Tab.

REM Fill a two-field form: username <tab> password <enter>
STRING tjscientist
TAB
STRING hunter2
ENTER

7. Modifier keys and combinations

Modifier keys — the ones you hold while pressing something else — are named, and Ducky Script’s syntax for “modifier + key” is simply putting them on the same line.

The modifiers

SHIFT
ALT
CONTROL   (or CTRL)
COMMAND   (the Mac ⌘ key)
WINDOWS   (or GUI — the Windows/Super key)

Modifier + key — same line:

GUI r                 REM Windows: open the Run dialog
CTRL c                REM copy
ALT F4                REM close the active window
GUI d                 REM Windows: show desktop
CONTROL ALT DELETE    REM the secure attention sequence

Documented multi-modifier combinations (the quick reference enumerates these as first-class):

CTRL SHIFT
ALT SHIFT
COMMAND CTRL
COMMAND CTRL SHIFT
COMMAND OPTION
COMMAND OPTION SHIFT
CONTROL ALT DELETE

So CTRL SHIFT ESCAPE opens Task Manager on Windows; COMMAND SPACE opens Spotlight on macOS.

INJECT_MOD (a 3.0 refinement, noted here for completeness) presses a modifier key by itself — e.g. INJECT_MOD WINDOWS taps the Windows key alone to open the Start menu, which a bare WINDOWS line followed by nothing does not reliably do across all hosts.

   The cross-platform reality
   ════════════════════════════════════════════════════════

   The SAME payload line means different things per OS:

   GUI r        Windows: Run dialog        macOS: nothing useful
   GUI SPACE    Windows: nothing useful    macOS: Spotlight
   GUI l        Windows: lock screen       macOS: (varies)

   A 1.0 payload that hard-codes GUI r only works on Windows.
   A robust payload either targets ONE OS deliberately, or —
   in 3.0 — detects $_OS first and branches (Vol 5).

8. The classic payload patterns

Everything above, assembled into the patterns you will write constantly. These are 1.0 — they run on every device.

The launcher (Windows Run dialog → command):

REM Open an elevated-or-not command prompt and run a command
DELAY 2000
GUI r
DELAY 500
STRINGLN cmd
DELAY 750
STRINGLN whoami

The PowerShell one-liner (the offensive workhorse shape):

DELAY 2000
GUI r
DELAY 500
STRINGLN powershell -NoProfile -WindowStyle Hidden -Command "<command here>"

The “type a whole script via clipboard” trick — faster and more reliable than typing a long script keystroke-by-keystroke, because the long part is one paste:

REM (1.0 style — set the clipboard, then paste)
GUI r
DELAY 500
STRINGLN powershell
DELAY 1000
STRINGLN Set-Clipboard -Value 'Get-Process | Out-File C:\Users\Public\p.txt'
STRINGLN powershell -Command "iex (Get-Clipboard)"

The macOS launcher (Spotlight → Terminal):

DELAY 2000
GUI SPACE
DELAY 500
STRINGLN terminal
DELAY 1500
STRINGLN whoami

Vol 13 is the full payload catalogue with worked, device-specific examples; this section is just to show the 1.0 core doing something.


9. Why 1.0 payloads break — typing blind

The defining limitation, stated plainly so every later volume can reference it: a 1.0 payload has no feedback. It cannot tell:

  • whether the OS has finished enumerating the device,
  • whether the window it is typing into has focus,
  • whether the last command succeeded or threw an error,
  • whether a UAC prompt, a dialog, or a notification stole focus,
  • what OS or keyboard layout it is even on.

Everything that makes a 1.0 payload robust is a workaround for this blindness:

TechniqueWhat it works around
Generous opening DELAYenumeration timing varies by host
DELAY after every focus-changing actionwindow focus is not instantaneous
ESCAPE / ESCAPE / ESCAPE at the startclears any stray dialog/menu state
Targeting one OS deliberatelya payload that branches needs 3.0
Keeping payloads shortevery line is another chance to desynchronise
Clipboard-paste for long contentone paste can’t desynchronise mid-way like 200 keystrokes can

This is the entire motivation for Ducky Script 3.0’s “smart payload” features (Vol 5) — $_OS detection and the WAIT_FOR_* lock-key waits exist to replace guesswork with confirmation. But the 1.0 core is still where most payloads live, because most payloads are short and most of the time a well-tuned DELAY is enough. Know the blindness; respect it; reach for 3.0 when the payload is long, branchy, or has to work across machines you can’t test on.


10. Resources

This is Volume 3 of an 18-volume series. Next: Vol 4 covers Ducky Script 3.0 — the structured language: VAR and the operator set, IF/ELSE conditionals, WHILE loops, FUNCTIONs, and the DEFINE preprocessor.