Projects

USB Rubber Ducky

A Cheeky Prank Device

Johann Wyss

Issue 18, December 2018

This article includes additional downloadable resources.
Please log in to access.

Log in

This project is for those of you who are known for being the practical joker in the home or office.

BUILD TIME: 2-3 HOURS
DIFFICULTY RATING: BEGINNER

Imagine your friend or colleague sitting at their desk typing out an important email or writing a report for an assignment, only to have weird and crazy things appear at random intervals. Their font randomly changes size, the caps lock key randomly toggles, or YouTube suddenly opens to a pop song from the late 1980’s from a guy called Rick, singing about never giving you up...

If you know someone who has a sense of humour and doesn’t shy away from a bit of light pranking this may be something you want to build.

THE BROAD OVERVIEW

A regular USB rubber ducky is basically a programmable keyboard emulation device that allows a person to rapidly enter keystrokes to quickly perform a task on a PC, which they usually need to do many times. For example, I have used them in the past to install Windows on new computer systems, all with the same network configuration settings, via Telnet. Having a rubber ducky means you don’t need to babysit the process and thus you’re free to do other tasks.

The good news for us pranksters is that you don’t need to use them purely in a productive sense. You can use them to have a little bit of harmless fun with like-minded friends.

Due to the simplistic nature of this project, it is fairly light on the hardware side. As all hardware is essentially handled by the single Digispark device, however, things will be more in-depth when it comes to the software and coding. I will provide as many examples of different functions as possible, which you can then adapt for your own custom pranks.

HOW IT WORKS

The heart of this project is a USB development board called the Digispark from a company called Digistump. They ran a very successful Kickstarter to develop and produce the Digispark, which is a completely open-source Arduino based development platform. What separates the Digispark from other Arduino based development boards is its onboard USB capabilities.

You can buy the Digispark board online from various vendors, including the Australian Distributor: https://www.gorilladistribution.com.au/product-category/arduino/digispark/

The Digispark is, however, little more than an ATtiny85 microcontroller with a funky bootloader called Micronucleus, which is another open-source project. This bootloader allows the device to emulate USB hardware and thus act like a keyboard.

The Fundamental Build:

The Prototype

Parts Required:Jaycar
1 × ATtiny85 MicrocontrollerZZ8721
1 × 1N4004 Diode*ZR1004
2 × 3.6V Zener DiodesZR1399
1 × Red LEDZD1690
1 × Green LEDZD0242
2 × 68Ω 1/4W Resistors*RR0544
2 × 330Ω 1/4W Resistors*RR0560
1 × 1.5kΩ 1/4W Resistor*RR0576
1 × 100nf Greencap or Ceramic CapacitorRG5125
1 × 4.7µf Electrolytic CapacitorRE6058
1 × USB Type-A PC-Mount SocketPS0916

*Quantity shown, may be sold in packs. You’ll also need a breadboard and prototyping hardware.

Digispark schematic from digistump.com

If you are fortunate enough to have already purchased your own Digispark board you can skip this build and move on to the main build. If you don’t have access to the Digispark I’ll show you how to make your own Digispark clone on a breadboard. Of course, it won’t be tiny and able to be sneakily inserted into a PC, but you could disguise it in a box perhaps, or hide it out of view with a USB cable connecting it to the PC.

You will need to get all of the components in the parts list. You will also need a breadboard, jumper leads and a USB cable. I have used my own USB breakout board in my prototype, but you could use a PCB mount socket available from local electronics retailers, and just bend the side tabs to make it fit into the breadboard.

Follow the Fritzing diagram shown here to assemble your prototype. Make sure you pay attention to the orientation of the ATtiny85 IC, electrolytic capacitor, the red and green LEDs, and the diodes.

With all the components properly in place, you can now move on to the programming step.

The Software

This project will require you to install Bootloader and Arduino IDE onto the Digispark. The bootloader is the code that needs to be programmed on the Digispark so it can act as a USB device. The Arduino IDE is the application where we will create and execute our code.

Micronucleus Bootloader

As I mentioned in the broad overview, the secret to this device is the Micronucleus bootloader. Micronucleus is a bootloader designed for AVR ATtiny microcontrollers with a minimal USB interface. It has a cross-platform, libusb-based program upload tool, with a strong emphasis on a compact bootloader.

The author suggests it could even be the smallest USB bootloader for the AVR ATtiny. You can find detailed information on where and how to download and install this bootloader at the following address: https://github.com/micronucleus/micronucleus

Programming the Digispark

With the bootloader installed on your ATtiny85 microcontroller, you can then install and set up the Arduino IDE on the microcontroller. Follow the comprehensive online instructions to download, install and set up the Arduino IDE 1.6.5+.

http://digistump.com/wiki/digispark/tutorials/connecting

The Main Build:

Rubber Ducky

You can pack your soldering iron and prototype hardware away because Digistump has done most of the work for us with their pre-assembled Digispark board. All we need to do is program it and house it in a 3D printed case. If you want to get straight into the coding, you can skip to the Software section.

3D PRINTED ENCLOSURE

The case for this project is as simple as it gets, it consists of a single piece that slides over the Digispark, with a little hot glue to fix it into place. This is largely because the device itself needs to fit flush against some USB ports on laptops, for example, which have contoured edges. Having it fully enclosed with a 3D print would prevent normal operation.

Using Crayons for added colour

I tried something different for this 3D print, I was told by a friend that they saw someone use melted crayons as a way to add colour to 3D prints and thought it would be useful to try. I modeled the ducky into the design and rather than tell my slicer to fill it with a different colour I left it as a void.

Once it was printed I used a hot air gun on medium heat and low airflow to melt a yellow crayon, allowing it to drip into the ducky impression. After it was thoroughly filled I used a razor blade to carefully remove as much of the bulge of wax as possible. I then used some fine grit P800 sandpaper to carefully sand the surface flat and smooth. I would recommend applying a clear coat to seal it and provide a better finish than what my build shows.

This is the device as it came off the 3D printer, showing the ducky void.
After removing the excess crayon and sanding.

THE CODE

You are probably keen to start programming, but I suggest you read the following Code section in its entirety before getting stuck into making your own programs.

Writing programs for the Digispark

In this section, I am going to list a few different functions you can perform using this device. The idea is you can pick and choose which types of events you want to happen.

I will also list them under two subheadings, the first one for “mildly annoying” pranks, which will include entering random phrases, toggling the caps lock key and tabbing in a document. These types of events will be obvious, however, difficult for the user to figure out what is going on.

The second will be far more "Anger Inducing", which includes things like opening a YouTube song, pretending to show a BSOD (blue-screen-of-death) or tricking the user into thinking their PC is updating.

Finally, after explaining and showing a few different styles, I will provide three working examples of a mixture of the listed styles.

MILDLY ANNOYING PRANKS

The following are the subtle types of events which the user may or may not see happening, this will ensure the device is left undetected for as long as possible.

CAPS LOCK TOGGLING: This code will simulate a press of the caps lock button.

DigiKeyboard.sendKeyStroke(57)

ENTER STRINGS OF TEXT: This code will type out all the text between the “ ”. Keeping the text to one or two characters will help reduce user suspicions, although having it type creepy or odd things may be worth getting caught too.

DigiKeyboard.print("Enter prank message");

SIMULATE A STUCK KEY: This could be a fun tool to tease online gamers. Consider using the W, A, S, or D key, which simulates a realistic function, so is less likely to get noticed. This will press the chosen key 25 times, which you can increase or decrease depending on your intentions.

for(int i =0; i < 25; i++)
{
DigiKeyboard.print("Enter stuck key here");
}

SIMULATE PRESSING A TAB KEY: This is a very simple and hard to detect prank. It simulates a random intermittent fault with the victim’s keyboard. It would be hard to detect, and as such, stands to not warrant much suspicion.

DigiKeyboard.sendKeyStroke(KEY_TAB); 

This keystroke does not form part of the standard keyboard.h library, as such you need to add the definition:

#define KEY_TAB      0x2b

PASTE CLIPBOARD DATA CTRL + V: As the title suggests, it pastes whatever is in the user’s clipboard at the time. This could have interesting results depending on what they have stored in the clipboard.

DigiKeyboard.sendKeyStroke
        (KEY_V, MOD_CONTROL_LEFT);

UNDO - CTRL + Z: How annoying would it be to have your previous efforts undone? Perhaps a perfectly worded sentence disappears, or your last correction replaced with the error.

DigiKeyboard.sendKeyStroke
        (KEY_Z, MOD_CONTROL_LEFT);

HIGHLIGHT TEXT IN DOCUMENT: This code will highlight the 5 previously typed text/letters. If you want it to highlight 10 letters, for example, replace the 5 in the code with 10. The user may see the keystrokes as they happen, however, they are unlikely to suspect there is a problem.

for(int i =0; i < 5; i++){
DigiKeyboard.sendKeyStroke
        (KEY_LEFT_ARROW, MOD_SHIFT_RIGHT);
DigiKeyboard.delay(20);
}

This keystroke does not form part of the standard keyboard.h library, as such you need to add the definition:

#define KEY_LEFT_ARROW    0x50

RANDOM BUTTON PRESS: This will randomly pick any alphanumeric key to press.

DigiKeyboard.sendKeyStroke(random(4, 40));

ANGER INDUCING PRANKS

These pranks are sure to arouse suspicion, but they are likely to produce some decent giggles.

OPEN A SPECIFIC WEBPAGE: This will open a web browser and go to a page you specify. It's obvious nature will certainly give the game up, so be creative to ensure a good giggle first time. Keep it clean though! Perhaps something crazy like watching paint dry: https://www.watchpaintdry.online/

DigiKeyboard.sendKeyStroke
        (KEY_R, MOD_GUI_LEFT);
DigiKeyboard.delay(600);
DigiKeyboard.print("www.diyodemag.com");
  DigiKeyboard.sendKeyStroke(KEY_ENTER);

THE RICK ROLL: Are you old enough to remember Rick Astley’s ‘Never Gonna Give You Up’? If you are, you are probably singing the song in your head now, right?!

This code opens the user’s web browser to a YouTube video in the TV format and also removes the windows control bar. This can be done with any video, perhaps Hanson’s MMMBop or Justin Bieber's "baby" could be an alternative to prank younger “victims”. Let’s hope the user has their volume turned up loud!

DigiKeyboard.sendKeyStroke
        (KEY_R, MOD_GUI_LEFT);
DigiKeyboard.delay(600);
DigiKeyboard.print("https://www.youtube.com/tv#/watch/video/control?v=dQw4w9WgXcQ&lis  t=RDdQw4w9WgXcQ&resume");
DigiKeyboard.sendKeyStroke(KEY_ENTER);
DigiKeyboard.delay(200);
  DigiKeyboard.sendKeyStroke(KEY_F11);

FAKE WINDOWS UPDATE: This opens up a web browser window to a page showing a very long and tedious Windows update screen, and then maximises the window. If the user sees it happen it will give it away and not fool them, but still a pretty good prank if the timing is right. Hopefully, they don’t call the IT department.

DigiKeyboard.sendKeyStroke
        (KEY_R, MOD_GUI_LEFT);
DigiKeyboard.delay(600);
DigiKeyboard.print("http://fakeupdate.net/win10u/index.html");
DigiKeyboard.sendKeyStroke(KEY_ENTER);
DigiKeyboard.delay(200);
  DigiKeyboard.sendKeyStroke(KEY_F11);

FAKE BLUE SCREEN OF DEATH: This will open up a browser window to a website that simulates a BSOD error message, if the user sees it happen it will certainly give the prank away. Timing will be key!

DigiKeyboard.sendKeyStroke
        (KEY_R, MOD_GUI_LEFT);
DigiKeyboard.delay(600);
DigiKeyboard.print("http://fakebsod.com/windows-8-and-10");
DigiKeyboard.sendKeyStroke(KEY_ENTER);
DigiKeyboard.delay(200);
  DigiKeyboard.sendKeyStroke(KEY_F11);

OPEN FACEBOOK AND POST A STATUS: Be cautious, some people take their social media very seriously. This is a very slow and very obvious script. The user will certainly know something is amiss with this running. This will only work if the user has their login credentials saved in their default browser too. Be kind!

DigiKeyboard.sendKeyStroke
        (KEY_R, MOD_GUI_LEFT);
DigiKeyboard.delay(600);
DigiKeyboard.print("www.facebook.com");
DigiKeyboard.sendKeyStroke(KEY_ENTER);
DigiKeyboard.delay(4000);
DigiKeyboard.print("p"); 
DigiKeyboard.delay(600);
DigiKeyboard.print("Funny status here");
DigiKeyboard.sendKeyStroke(KEY_ENTER);
DigiKeyboard.delay(4000);  
DigiKeyboard.sendKeyStroke
  (KEY_ENTER, MOD_CONTROL_RIGHT);

Program 1: All Cases

My suggestion would be to slowly increment from the mildly annoying and less obvious functions listed above, progressing to the more intrusive and obvious anger inducing options.

The code will start off only having one option and that is to toggle the caps lock, however, after doing that 100 times it will increase the number of options by one. Meaning, it will then have two options to randomly choose, which in our case will be between toggling the caps lock and pressing a random key.

This will continue until all 13 options are available for the program to randomly pick.

I’m doing this by using ‘case’ statements. Each option is designated its own case, numbered from 1 to 13, at an approximate level of obviousness.

Each time any case is run, it increments a counter by 1. When that counter equals the predefined repeat limit, the number of available cases increase by one.

Bear in mind, this is just an example of how you can use this device. You can choose to just use one of the cases or your own selection of cases. For example, if you just wanted a device that would quickly post a Facebook status update you can certainly modify the code to just do that.

SETUP

Here I have defined some key operational requirements, which you can alter to make the device function as you want.

maxCase = the number of cases the program can randomly select from. My example has 2 random functions.

totalCase = the total number of cases. If you add more cases, you simply need to modify this number to suit.

Repeat = the number of cases that have to run before the program can add another case option.

TIMEDELAY = the amount of time that must elapse before the program runs again. 1000 equals one second, so the default of 20000 is about 20 seconds. This speed means the program has access to another case every 30 minutes or so. We can roughly calculate the duration using the following formula:

(repeat × (TIMEDELAY/1000))/60sec

= (100 × 20sec)/60sec

= 33.33mins

This would mean approximately 7 hours until all cases were available.

#include "DigiKeyboard.h"
#define KEY_TAB      0x2b
        // Keyboard TAB
#define KEY_LEFT_ARROW    0x50
        // Keyboard LeftArrow
#define KEY_L_BRACKET    0x2F
        // Keyboard [ and {
#define KEY_F11      0x44
        // Keyboard F11
int maxCase = 2;
        // Maximum number of current used cases
int totalCase = 13;
        // The total number of available cases
int repeat = 100;
        // Number of loops before adding new case
long randNumber;
int count = 0;
const int TIMEDELAY = 20000;
        // The delay before the program loops
void setup() {
  DigiKeyboard.delay(200);
  DigiKeyboard.sendKeyStroke(0);
  randomSeed(analogRead(0));
        // Remove this if you find your code seems to consistently pick a particular case.
  }

LOOP

This code section is too long to list in our mag, but is available for download on our website. It pretty much just lists each of the possible functions and assigns it to a case.

The code forces a reset once all cases have been included.

Program 2: Subtle, for Maximum Effect

For this option, I have written a program for maximum long-term pranking effect. It will use fewer examples and will revolve mostly around single key inputs to be subtle and avoid too much suspicion.

It uses similar use cases from our previous program example, however, all available cases will be selectable from the start of the program and they will be randomly chosen using a random function.

I have added a 5-minute delay to the start of the program so that the device can be left in a victim’s PC for up to 5 minutes before it activates. This stops the program interfering or preventing the victim from logging in. You can change this delay to suit your application.

I personally found this to be the ideal prank program for an office type environment, where a little “cubicle warfare” is required. It certainly makes using your computer a nightmare. Just make sure that you include the IT department in on the joke, the last thing your boss wants is for staff to start throwing out “faulty keyboards”.

SETUP

You can set the TIMEDELAY constant, which is the delay between repeating the loop (i.e the time between keypresses). 20000 = 20 seconds, adjust this as you see fit.

If you want an instant plug-in annoyance device you can consider removing the final delay. The delay is designed to allow the user to log in before the device becomes active.

maxCase is incremented by 1 as the switch function is using the random function to pick the case number. The random function picks a value between (min , max) with min being inclusive and max being exclusive. i.e in our case, a number between (1, maxCase) which is 1 (inclusive) and maxCase 3 (exclusive). Since the max number is exclusive we need to increment the maxCase variable by 1 for correct operation.

#include "DigiKeyboard.h"
#define KEY_TAB    0x2b  
        // Keyboard TAB
int maxCase = 3;
        // Max No. of use cases +1
int randNumber;
const int TIMEDELAY = 20000;
        // Delay before program loops
void setup() {
  DigiKeyboard.delay(200);
  DigiKeyboard.sendKeyStroke(0);
  maxCase ++;
  delay(300000);                
        // Delay before user logs in
  }

LOOP

Here the code simply picks a random number between one and the max case figure. The result of that function decides which case is used. After the program runs the case, it then enters the TIMEDELAY, which the user can adjust in the setup.

void loop() {  
  randNumber = random(1, maxCase);  
  switch (randNumber){
  
  case 1:    // Toggles the caps lock button
  DigiKeyboard.sendKeyStroke(57);
  break;
  case 2:    // Random single button press
  DigiKeyboard.sendKeyStroke(random(4, 40));
  break;
  
  case 3:    // Tab Button
  DigiKeyboard.sendKeyStroke(KEY_TAB); 
  break;  
  default:
  break;
  }
delay(TIMEDELAY);  
  }

Program 3: Instant Pranking

By far the simplest of the options. This code is designed for the impatient prankster that wants a giggle straight away. This would be best for one of the more creative cases, like the Facebook status update or the Windows update screen, rather than the simpler ones that may not arouse suspicion.

This is a very simple way to make sure the program only runs once. The while (i==1) statement will continue to run what is inside the loop. Once it performs what we wanted the program to do, we simply change 'i' to any other value other than 1. This means it can’t ever get back into this loop to run again until ‘i’ is changed back to 1.

I wrote this code so that you can put any of the cases here and run them just once. Go ahead and try a few out.

SETUP

#include "DigiKeyboard.h"
int i = 1;
void setup() {
  DigiKeyboard.delay(200);
  DigiKeyboard.sendKeyStroke(0);
  }

LOOP

void loop() {  
  delay(500);
  while(i==1){  // Enter your chosen case here
  DigiKeyboard.sendKeyStroke
        (KEY_R, MOD_GUI_LEFT);
  DigiKeyboard.delay(600);
  DigiKeyboard.print("www.facebook.com");
  DigiKeyboard.sendKeyStroke(KEY_ENTER);
  DigiKeyboard.delay(4000);
  DigiKeyboard.print("p"); 
  DigiKeyboard.delay(600);
  DigiKeyboard.print("I got punked");
  DigiKeyboard.sendKeyStroke(KEY_ENTER);
  DigiKeyboard.delay(4000);  
  DigiKeyboard.sendKeyStroke
        (KEY_ENTER, MOD_CONTROL_RIGHT); 
  i = 2;   
  }  
}

TESTING

To test my project, I disabled the Windows key on two of my older laptops; one running windows 7 and the other running Windows 8. I programmed two Rubber Ducky’s and inserted one in each machine with a text editor open.

I then allowed the program to run overnight. The next morning, I discovered that both devices, despite using a random generator seeded by a floating analog read, tended to always select a higher case number.

The most recent case available had a significantly higher chance of occurring. To counter this, I removed the seeding and retested the devices in the same way. As was expected, both produced identical results with the same keystrokes chosen at “random”. This does not in anyway affect the operation of the device

Whilst I can’t guarantee that every code will work with every Windows machine and OS variant, the clear majority will. However, I should point out that some public computers at work or school etc. may not allow the use of the run command. This will limit the number of cases that will work correctly.

WHERE TO FROM HERE?

Go ahead and test all of the prank cases, experimenting with different settings such as delays, messages, etc. Perhaps even design your own custom pranks.

Even though we have designed this to be a fun prank device, it could be adapted to some practical uses as well. I originally used this device to post sensor values to Twitter, for example, as a quick and easy way to get notified about relevant temperature and humidity data.

However, not wanting to leave my computer running constantly this wasn’t ideal for my application. With that said, it could be used nicely with a Raspberry Pi, assuming you don’t know how to program in Python.