DEV Community

Cover image for Rubber Ducky clone with Pro Micro micro controller
Avni
Avni

Posted on

Rubber Ducky clone with Pro Micro micro controller

⚠️ Disclaimer

This project is for educational purposes only.

Devices like the Rubber Ducky and its DIY clones can be powerful tools for penetration testing and automation but they should only be strictly used on systems you own or have explicit permission to test.

The Idea

The idea for this project came while watching a movie where the main character wanted to damage a bank that caused problems to his parents, so he went inside the bank pretending to be a British business man that wanted to create an account at their bank, he "accidentally" pushes the pen case to the ground so he can plug a tiny USB device in the computer. Once he does that the bankers monitor is blocked and you can see code being executed with lightning speeds.

So I had to find out what that tiny USB device was that did all of this chaos. I researched a bit and it turned out to be a Rubber Ducky, they were on sale but lets be real, when you are a student and on a budget you aren't going to spend $100 on a USB that acts as a keyboard and mouse, you have to improvise.
So I said lets try and do this myself with the resources I had.

Resources

  • Pro Micro with 32u4 Chip
  • Slide Switches (Pack of 40)
  • DuPont female cables (Pack of 40)

Total: ~$30

The Process

Wiring the switch

I first started with the switch. Out of the pack, I had two types of switches. One had big pins that didn't fit the DuPont cable, and the other one had small pins and holes for connecting wires. Naturally I went with the second one since I had no other choice. I took 1 DuPont cable and cut it in half with pliers and stripped about 1.5 cm of insulation covering the cable inside. Then I tied one half of the cable to the middle pin of the switch, and the other one to an outer pin.

The Schema:



Why the switch?

Once the code has been uploaded to the Pro Micro, it cannot be plugged into your computer to change the code without causing the payload to be executed.

So this switch acts like a mode selector:

  • Left: Programming mode (safe to upload new code)
  • Right: Execution mode (it runs the payload once plugged in)

Programming the board

Now comes the fun part...programming!

I used the Arduino IDE to make the write and upload the code into the board.

The setup

  1. Tools -> Board -> Boards Manager
  2. Select "Arduino Leonardo" (it uses the same bootloader as the Pro Micro)
  3. Choose your port and board
  4. Create a new sketch

This is how it should look like when you first start your project.

Now we are going to start by including the libraries.

#include <Keyboard.h>

void setup() {

    // put your setup code here, to run once:
}



void loop() {

    // put your main code here, to run repeatedly
}
Enter fullscreen mode Exit fullscreen mode

We will include the Keyboard library so the Pro Micro board can act as a Keyboard.
Next we need to act logic to the switch.

Adding the mode switch logic

#include <Keyboard.h>

const int switch_mode = 2; // You can change this depending on which pin you wired the middle pin of the switch

void setup() {

    pinMode(switch_mode, INPUT_PULLUP); // Normally HIGH, LOW when switch connect to GND (When we slide it to the left)

    bool execute_mode = (digitalRead(switch_mode) == LOW);
    if(!execute_mode){
        // Off / Standby (Payload doesn't execute)
        // So it gives us the opportunity to change and upload new
        // code to the board
        return;
    }

    // if it's on the other side then we will execute code down here



}



void loop() {

    // put your main code here, to run repeatedly:



}
Enter fullscreen mode Exit fullscreen mode

Now the board can tell weather to execute the payload or to stay idle based on where the switch is staying.

Writing the payload

Here's a more complete version that opens the terminal(on Linux) and executes whoami

#include <Keyboard.h>

const uint8_t switch_mode = 2; // D2 (switch middle)
const unsigned long WAIT_SHORT = 300; // short pause
const unsigned long WAIT_MED = 550; // medium pause

void attempt_open_terminal() {
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press(KEY_LEFT_ALT);
    delay(30);
    Keyboard.write('t');
    Keyboard.releaseAll();
}

void send_payload() {
    delay(WAIT_MED);

    Keyboard.begin();
    delay(100);
    Keyboard.println("whoami");

    delay(100);
    Keyboard.end();
}



void setup() {
    pinMode(switch_mode, INPUT_PULLUP); 
    // HIGH normally, LOW when switch connects to GND

    delay(50);

    bool executeMode = (digitalRead(switch_mode) == LOW);
    if (!executeMode) {
        // Off / Standby (Payload doesn't execute)
        return;
    }

    delay(1000); // give OS/USB time to detect the HID device
    attempt_open_terminal();
    send_payload();
}

void loop() {
// nothing repeated
}
Enter fullscreen mode Exit fullscreen mode

Breaking it down

We added the attempt_open_terminal and send_payload_commands functions. Lets go through each one of them and see what they do.

  • attempt_open_terminal() This function simulates pressing CTRL + ALT + T, the linux shortcut to open the terminal.

It uses the Keyboard library to press multiple keys at once (CTRL + ALT + T) and then release them, just like a real user would do.

  • send_payload() Once the terminal opens, this function executese the payload. Here, it simply types whoami, which prints the currently logged-in user.

You can replace that line with any other commands, like opening websites, or running system commands (ethically, of course).

Reference

Top comments (0)