Since the beginning of Keystroke Injection attacks, dating back to the origins of DuckyScript 1.0 over a decade ago, conventional wisdom has been to always begin a payload with the simple line:
TL;DR: If you've ever plugged in a keyboard and started pressing keys until you saw them appear - this is the nearly arbitrary delay we are trying to solve for.
Simply put, the USB Rubber Ducky is capable of injecting keystrokes faster than the target is ready to accept them in a usable fashion. While the USB Rubber Ducky boots, processes, and starts running its payload almost instantly, the target must enumerate and set up the new USB HID device as necessary.
On very old computers, USB device setup could be as much as 1 to 2 seconds. Therefore, a 3000 ms delay would in the majority of cases ensure that your payload would execute more reliably across varying targets.
But what about modern, fast computers? Why wait so long? Further complicating the problem; many systems will offer up the communication channel with the USB Rubber Ducky at the protocol level before the operating system itself starts accepting usable input.
While faster, omitting a "better safe than sorry" (better slow than broken) DELAY at the beginning of the your payload can often result in an "ello, World!" rather than a "Hello, World!". For a payload as simple as the above example it may not be the end of the world; but for your 5 second Mr Robot Style hack while on an engagement — it very well could be the difference between success and a very alarm bell ringing failure.
Even going as far as to custom tailor a finely tuned boot DELAY for your payload and the exact target system you'll find that the variance between USB Rubber Ducky "boots" (or payload runs) is enough to put you right back into the ballpark of +/- 1000ms. Considering many actual flash drives take significantly longer to enumerate on some systems, we're full circle back to "Just add a
DELAY 3000" for any hope of near 100% reliability and call it a day. Until...
Because DuckyScript 3.0 includes the logic necessary to make programmatic decisions, as well as awareness of the Lock Key states (that we abuse in our Keystroke Reflection attack) we can instruct our payload to
DELAY only for as long as is necessary before reliably injecting meaningful keystrokes. That's exactly what we've done with the
Simply by being added to the top of your payload, this extension waits for the defined response delay until either the state of
CAPSLOCK has been confirmed on, or the defined iteration limit has been reached. The minimum response
DELAY is set to a default of 25 ms; a value we have found to be optimized. In our testing across a broad range of systems, this is the lowest value which produces the fastest results without additional unnecessary iteration.
This means one of three things has happened before the rest of your payload runs;
CAPSLOCKturned on -
$_CAPSLOCK_ON== TRUE being a side effect of the operating system syncing the current
CAPSLOCKstate to the newly connected keyboard: the USB Rubber Ducky. While this is not a full circle confirmation like the first possible outcome, it is sufficient enough indication that the host will accept further keystrokes from the USB Rubber Ducky.
We put the DETECT_READY extension to the test by adding some debugging instrumentation. In this case, by importing the TRANSLATE extension, we are able to type out how long after connection and enumeration the target took to be ready for reliable keystroke injection.
This bare metal Dell XPS 13 machine is running on modern Intel i7 hardware.
Result: 25 milliseconds! 99.17% reduction
Similarly, our Linux example is also running on the same hardware in a VM
Result: 100ms; a 96.67% reduction
How about something ancient? For this test we dusted off an old ASUS Eee PC 701 — a 2007 era netbook with a Intel Celeron CPU underclocked to 630 MHz!
Result: ~400ms; a 86.67% reduction
Mobile targets such as iOS and Android need extra attention. While the
DETECT_READY extension will only
DELAY so long as the target is not prepared to accept keystrokes, in our experience mobile devices still require extra time to close their on-screen keyboards once a physical keyboard has been recognized by the OS.
Additionally MacOS traditionally does not sync or reflect lock key states; The iteration limit built into the extension by default ensures that the payload continues after a maximum
DELAY of 3000 ms, the previously held conventional wisdom, which in experience is sufficient for most targets. The value may be increased to achieve the highest possible compatibility in the case that the target requires a very slow driver download and installation — something that may be possible when brute forcing VID and PID values. That said, this is very unlikely for most known keyboard identifiers in our experience.
By using the extension architecture of DuckyScript 3.0, all payload authors benefit from the
DETECT_READY capabilities while having the flexibility to modify it to their specific requirements.
DETECT_READY extension can be found from the USB Rubber Ducky payload repository at https://github.com/hak5/usbrubberducky-payloads/tree/master/payloads/extensions
DETECT_READY in your own payload, simply begin typing
EXTENSION DELAY_READY and select the auto-complete suggestion from within PayloadStudio; it will automatically include the latest version.
Placing this at the top of your payload in lieu of the traditional
DELAY 3000 will produce the results mentioned above. Get ready to enjoy both faster and more reliable payload execution!
Considering that Apple operating systems are the main flavor of target that won't take advantage of the enhanced functionality provided by
DETECT_READY, why not continue to improve within the scope where it is already applicable? If you've followed along so far you might have taken note that many operating systems that do reflect lock keys also (generally) sync lock states on connection of a new keyboard. This being part of what we can consider to be the setup process, it should be both faster and entirely passive to detect ready on these systems simply by detecting the initial update of the lock states. Thus
PASSIVE_DETECT_READY is born.
We're already detecting either the first usable input, or the end of the setup process...
Conveniently, the USB Rubber Ducky also happens to implement a novel, entirely passive, driver level, Windows detection - instantly during the setup process; not only can this process reliably become EVEN FASTER on Windows targets - we can also make a very simple yet powerful OS determination at the exact same time...
PASSIVE_WINDOWS_DETECT does exactly this for you.
Authors: Dallas Winger, Darren Kitchen
A two second HID attack against Windows and Mac that launches the website of your choosing. That's by far the most effective security awareness payload for the USB Rubber Ducky.