Analyse radiofréquence d’une clé de voiture

MISC n° 086 | juillet 2016 | Florent Poulain
Creative Commons
  • Actuellement 0 sur 5 étoiles
0
Merci d'avoir participé !
Vous avez déjà noté cette page, vous ne pouvez la noter qu'une fois !
Votre note a été changée, merci de votre participation !
L'analyse des données transmises par une clé de voiture permet de déterminer les paramètres de radiofréquence et de modulation utilisés. De l'outillage abordable est mis en œuvre afin d'intercepter le code émis par la clé, avant de le rejouer pour déverrouiller le véhicule ciblé.

La démocratisation des outils d'analyse radiofréquence, grâce à la radio logicielle, rend accessible aux hackers toute une nouvelle surface d'attaque. La sécurité de la voiture « connectée » est également sous les feux de la rampe depuis quelque temps, comme on a pu le voir notamment au travers du piratage à distance de véhicules du groupe Fiat-Chrysler par les chercheurs Charlie Miller et Chris Valasek [JEEPHACK] ou celui du système OnStar par Samy Kamkar [OWNSTAR].

La prise en main de matériels et logiciels populaires de Software Defined Radio est l'occasion parfaite d'étudier la sécurité d'une télécommande automobile.

Note

Définition

Dixit Wikipédia, une radio logicielle, en anglais Software Defined Radio, est un récepteur et éventuellement émetteur radio réalisé principalement par logiciel et dans une moindre mesure par matériel.

Le cheminement proposé amènera à capturer un code émis par la clé et à déterminer la fréquence utilisée par le signal radio analogique, puis à convertir ce signal en son équivalent numérique : les données « binaires ». Cela implique de retrouver de quelle façon le signal analogique encode ces dernières. Notamment la modulation employée, à savoir le type de variation du signal radio servant à encoder les bits du code, comme la variation de fréquence, de phase, ou d'amplitude. Et finalement établir la vitesse de transmission, avant de pouvoir commencer à émettre soi-même.

1. Détermination de la fréquence

Quelques requêtes sur les moteurs de recherche révèlent rapidement que le fabricant utilise des fréquences de 315 Mhz ou 433,92 Mhz selon la région du monde à laquelle le véhicule est destiné.

Une écoute avec le HackRF One et le logiciel GQRX sur ces deux fréquences précise rapidement que notre clé utilise la bande 433,92 Mhz, comme le montre le pic observé sur le spectre lors de la pression du bouton d'ouverture (figure 1).

Figure 1 : Pic de fréquence à 433,92 Mhz.

Commençons une checklist des prérequis pour démodulation, qui servira de fil conducteur :

- [x] Fréquence : 433,920 Mhz ;

- [ ] Modulation et paramètres.

2. Rejeu simple avec le HackRF One

Avant d'aller plus loin dans l'analyse des données transmises, la première ouverture de la voiture se fait uniquement avec le HackRF One(https://greatscottgadgets.com/hackrf/), créé par Michael Ossmann. Cet équipement de radio logicielle (Software Defined Radio) peut opérer de 1 Mhz à 6 Ghz, fonctionne en réception et en émission (en half-duplex), et est compatible avec de nombreux logiciels de SDR comme GNU Radio, SDR# ou GQRX.

Le programme compagnon hackrf_transfer permet de faire très simplement de la capture et du rejeu avec les options -r et -t. Cela a l'intérêt non négligeable de permettre ces attaques de rejeu sans se soucier des paramètres de traitement du signal comme le baud rate, la modulation, etc.

Capture du signal, loin de la voiture afin qu'elle ne capte pas le code transmis par la clé (nous reviendrons plus loin sur la raison de cela) :

hackrf_transfer -r 433.92mhz-capture.raw -a 1 -p 1 -f 433920000

Rejeu du signal, à proximité de la voiture :

hackrf_transfer -t 433.92mhz-capture.raw -a 1 -p 1 -f 433920000

Flash des clignotants, bruits de serrure caractéristiques, c'est ouvert !

Ici, les options -a, pour activer l'amplificateur RX/TX et -p, pour activer l'antenne, se sont avérées nécessaires pour que le signal soit suffisamment puissant pour être « entendu » par la voiture. Sans ces options, rien ne se passait, même en se tenant très près du véhicule.

D'autres options plus fines permettent de contrôler le gain en émission ou réception (voir -l, -g, -x), mais n'ont pas été nécessaires dans le cas présent.

3. Détermination du type de modulation

À présent, il est nécessaire de déterminer les différents paramètres de traitement du signal.

Une option rapide pour avoir une première idée de l'allure du signal est baudline (http://www.baudline.com/download.html).

Un article du blog Kismet Wireless [KISBLOG] donne quelques astuces intéressantes pour l'utilisation de baudline, notamment en cas de segfault du programme si le fichier à lire est trop gros (huh !).

Revenons simplement sur les paramètres de chargement qu'il convient d'utiliser pour lire les fichiers de données brutes produits par hackrf_transfer. Le sample rate n'avait pas été précisé, hackrf_transfer a donc utilisé la valeur par défaut de 10 Msps (Millions Samples Per Second), qu'on reporte donc dans les paramètres de baudline. Configurer deux channels, cocher Quadrature et Flip complex, utiliser 8 bit linear (unsigned) comme format de décodage. L'explication de ces derniers paramètres est donnée sur le blog Kismet référencé ci-dessus.

Une fois le dialogue d'ouverture de fichier validé, l'affichage en figure 2 se présente.

Figure 2 : Visualisation du signal dans baudline.

Il est alors recommandé de jouer avec le dialogue Color aperture (clic droit > Input >Color aperture), ainsi qu'avec le zoom ([Alt + flèches haut et bas]), pour obtenir une vue plus claire et précise du signal, comme dans la figure 3. Celle-ci montre le début du signal, à gauche, et une séquence de bits un peu plus loin, à droite.

Figure 3 : Début et milieu du signal vus dans baudline.

Premier constat, le signal effectue des sauts de fréquences réguliers, entre deux fréquences distinctes, ce qui indique l'utilisation d'une modulation 2-FSK.

Le début du signal semble être une longue succession de 0 et de 1. Il s'agit d'un préambule pour avertir le récepteur de la voiture qu'un code d'ouverture ou de fermeture des portes va suivre. En descendant plus bas dans le signal, on repère facilement l'endroit où ce pattern répétitif se termine pour laisser la place aux données réellement significatives. Voir fenêtre de droite sur la capture.

Checklist mise à jour :

- [x] Fréquence : 433,920 Mhz ;

- [x] Modulation : 2-FSK ;

- [ ] Déviation ;

- [ ] Bitrate.

4. Détermination des paramètres de modulation: déviation, bitrate

Connaissant le type de modulation utilisé, il faut maintenant déterminer la déviation et le bitrate ou symbol rate.

La déviation est le décalage exprimé en Hz entre la fréquence centrale, soit 433,920 Mhz et une des deux fréquences utilisées par la modulation 2-FSK.

Le symbol rate est la quantité de symboles transmise en une seconde par la modulation choisie. Le bitrate est la quantité de bits transmise en une seconde par le signal. En modulation 2-FSK, le signal ne peut encoder que deux valeurs à un instant donné, 0 ou 1. Le symbol rate et le bitrate sont donc identiques. Pour prendre un exemple différent, en modulation 4-FSK, qui utilise 4 fréquences différentes pour encoder deux bits par symbole, le bitrate sera donc le double du symbol rate.

Il est possible de rester dans baudline pour déterminer le symbol rate, ou se servir de Audacity.

Le principe est identique dans les deux logiciels, on sélectionne à la souris un certain nombre de symboles (40 dans les deux cas ci-dessous) et on affiche le nombre de secondes ou de samples de la sélection correspondante (figure 4).

Connaissant le sample rate de la capture (106 samples/s) et avec des règles de trois, on calcule dans les deux cas un symbol rate d'environ 2000 symboles par seconde.

Figure 4 : Détermination du symbol rate du signal.

Nouvelle mise à jour de la checklist :

- [x] Fréquence : 433,920 Mhz ;

- [x] Modulation : 2-FSK ;

- [ ] Déviation ;

- [x] Bitrate : 2000 bits/s.

Pour déterminer la déviation, un autre outil est requis, le niveau de zoom offert par baudline sur ce fichier étant un peu juste pour une mesure assez précise.

Il est alors temps de sortir le couteau suisse de l'analyse radiofréquence, GNU Radio. Cet outil puissant offre de nombreux « blocs » destinés au traitement radio : capture, filtrage, visualisation, démodulation, émission, conversions, etc., qui peuvent être reliés en chaîne au gré de l'utilisateur dans une interface graphique nommée GNU Radio Companion pour aboutir au traitement voulu. Un graphe validé par l'outil peut alors être converti en script Python et utilisé tel quel ou modifié.

Note

Attention, les exemples qui suivent se basent sur une nouvelle capture faite avec un sample rate de 5 millions de samples par seconde au lieu de 10 précédemment.

Ce premier graphe, en figure 5, permet de visualiser le signal.

Figure 5 : Graphe GNU Radio de visualisation du signal.

Le bloc clé ici est le « Frequency Xlating FIR Filter » qui sert trois objectifs :

- décimer la capture par 20, c.-à-d. on ne retient qu'un sample sur 20. Les blocs suivants devront alors tenir compte du nouveau sample rate de 250 k (5 M / 20) ;

- translater la fréquence centrale du signal intéressant de 90 kHz pour le recentrer. Effectivement, afin d'éviter le phénomène « DC Spike » [DCSPIKE] du HackRF One, la capture a cette fois-ci été faite à 433,82 Mhz. Malgré ce déplacement de 100 kHz, c'est une valeur de 90 kHz qui a le mieux centré le signal émis par la clé. Cela veut simplement dire que la puce radio de la clé n'émet pas de façon parfaitement centrée sur sa fréquence de fonctionnement annoncée ;

- appliquer un filtre passe-bas pour garder une bande passante d'un peu plus de 25 kHz autour de la fréquence centrale. Le filtre est défini ainsi dans le bloc firdes_filter: firdes.low_pass(1, samp_rate, bandwidth, bandwidth/4).

La raison de l'utilisation d'un filtre passe-bas plutôt qu'un filtre passe-bande, qui pourrait sembler plus logique puisque nous cherchons à isoler une portion autour du « pic », est que le signal capturé est centré sur zéro par le bloc « osmocom source ». Le filtre passe-bas est effectif à sa fréquence de coupure en « valeur absolue », c.-à-d. à la fois dans les fréquences négatives et positives de notre spectre recentré, ce qui élimine en pratique le besoin d'un filtre passe-bande.

Il résulte de l'exécution de ce graphe GNU Radio une visualisation du signal dans le bloc « WX Gui FFT Sink » bien centrée entre les deux fréquences utilisées par la modulation 2-FSK, et un filtrage du signal afin de garder uniquement cette partie intéressante du spectre.

Figure 6 : Détermination de la déviation grâce à GNU Radio.

Avec l'option « Peak Hold» du bloc de visualisation, il est aisé d'identifier la déviation utilisée par la modulation 2-FSK. En figure 6, le premier pic est constaté à environ -31 kHz par rapport à la fréquence centrale, et le second pic à environ 34 kHz. En tenant compte de l'imprécision de cette méthode, on se trouve donc à peu près avec 60 kHz de différence entre les deux pics, soit une déviation de 30 kHz.

À ce stade, la checklist de démodulation est maintenant remplie :

- [x] Fréquence : 433,920 Mhz ;

- [x] Modulation : 2-FSK ;

- [x] Déviation : 30 kHz ;

- [x] Bitrate : 2000 bits/s.

5. Démodulation manuelle du signal

Le graphe suivant est construit pour effectuer la démodulation complète du signal. On ignore ici toute notion de préambule ou de sync word, tout est démodulé. Les codes intéressants envoyés par la clé seront donc « noyés » au milieu de données non significatives, le « bruit ambiant ».

Figure 7 : Graphe GNU Radio de démodulation du signal.

Au graphe précédent est rajouté un bloc « Quadrature Demod » qui se charge de la démodulation 2-FSK.

Les blocs gain_fsk et modulation_index sont définis comme suit, en fonction des blocs baud_rate et deviation_hz qui ont été renseignés avec les valeurs trouvées précédemment. Les formules viennent du wiki GNU Radio [grcwiki] :

- modulation_index = deviation_hz / (baud_rate / 2) ;

- gain = samp_per_sym / (pi * modulation_index).

Le bloc « Clock Recovery MM » sert à rééchantillonner notre signal afin qu'un symbole (ou bit) corresponde à 125 samples après décimation.

Pour s'assurer de la cohérence, on retrouve bien :

- 125 samples par symbole, multiplié par 20 = 2500 samples par symbole avant décimation ;

- et 2500 samples multipliées par le baud rate ou bit rate de 2000 symboles/s = 5.000.000 samples/s, ce qui correspond au sample rate de 5M utilisé dans le graphe GNU Radio. L'ensemble est cohérent.

Les données démodulées sont écrites dans le fichier dumpcodes.dat que nous allons maintenant examiner. Pour commencer le flux de données brutes est transformé en format humainement lisible, qu'on voit apparaître à la dernière ligne, le « train binaire » :

[1] pry(main)> f = File.open('/tmp/dumpcodes.dat', 'rb')

=> #<File:/tmp/dumpcodes.dat>

[2] pry(main)> dat = f.read()

[...]

[4] pry(main)> d = dat.unpack("C*").map {|x| x.to_s}.join

=> "00110001001000011000101000111001101[...]

Et finalement, on recherche le préambule dans ce flux. Pour rappel, ce préambule a été repéré dans baudline ou Audacity, au début du signal. Trois occurrences sont trouvées, correspondant à plusieurs appuis sur les boutons de la clé, ce qui confirme la bonne démodulation du signal :

[5] pry(main)> d.scan(/000000001010101010101010\d{450,450}/)

=> ["0000000010101010101010[...]000010100010100010111111011100100010010111110110000010001",

"0000000010101010101010[...]011100011111000101011101110111010101000111000001111010011",

"0000000010101010101010[...]011001101011000011000101000001111001000111011101000001110"]

Visiblement, le code change à chaque appui de bouton. Ce système de code tournant ou rolling code est destiné à contrer des attaques de rejeu simple. Le récepteur de la voiture et l'émetteur de la clé utilisent un algorithme de type PRNG « pseudorandom number generator » et une valeur initiale synchronisée selon une procédure constructeur. L'émetteur envoie à chaque appui le code suivant dans la séquence cryptographique, que le récepteur compare de son côté en effectuant le même calcul. Ainsi, tout rejeu d'un code capturé est théoriquement impossible.

C'est pour cette raison que le rejeu avec le HackRF One, dont il était question plus haut, devait se baser sur un code capturé à bonne distance du récepteur.

6. Utilisation du YardStickOne

Le rejeu de ces codes sans sortir de GNU Radio serait parfaitement possible, en créant un graphe effectuant le traitement inverse. Cependant, pour faciliter les choses et présenter un nouvel outil, nous avons souhaité utiliser le YARD Stick One (https://greatscottgadgets.com/yardstickone/) qui semblait parfaitement adapté au besoin.

Cette clé USB radio créée par Michael Ossmann – grâces lui soient rendues de ses multiples contributions à la SDR ! – utilise une puce Texas Instruments CC1111 qui opère aux bandes de fréquences de 300-348 MHz, 391-464 MHz et 782-928 MHz. La puce TI est de plus capable d'effectuer les modulations et démodulations ASK, OOK, 2-FSK, 4-FSK et MSK, ce qui permet d'obtenir directement les données binaires démodulées.

Pour compléter le tableau, il est livré flashé avec un firmware RfCat(https://bitbucket.org/atlas0fd00m/rfcat) créé par Atlas, ainsi que la bibliothèque Python et le shell interactif qui vont avec, très pratiques. Avec un minimum de configuration, un débutant en radio logicielle peut très vite découvrir les bases et émettre ou recevoir des signaux selon différentes modulations. On ne saurait trop recommander de lire l'excellent support de workshop donné par Atlas à la BlackHat 2012 pour obtenir une bonne introduction aux capacités de RfCat [RFCATWKS].

En particulier, outre les fonctionnalités utilisées dans les scripts donnés plus bas et celles données dans la bannière affichée par rfcat à son lancement, les fonctions de découverte de rfcat ont été assez utiles ainsi que l'aide intégrée :

d.discover()

d.discover(IdentSyncWord=True)

help(d)

Le mode discover peut être utilisé pour avoir un premier test des paramètres déterminés auparavant. On voit effectivement des données ressemblant à nos codes apparaître dans le bruit ambiant :

$ rfcat -r

In [1]: d.setFreq(433920000)

In [2]: d.setMdmModulation(MOD_2FSK)

In [3]: d.setMdmDeviatn(30000)

In [4]: d.setMdmDRate(2000)

In [5]: d.discover()

(press Enter to quit)

[...]

(1456240472.012) Received: 995715d0b90123408c844c0011617ac73f225408a5326301e0322fac9751

(1456240472.135) Received: b8edfb8f402ccc0dd83800aaaaaaaaaaaaaaaaaaaaaaaaaaa5aa6aa66aa6

(1456240472.260) Received: 0d2b2cacad34aab4acd32cb534cb2b4ab4b554d2b34d49280e7af85cce33

(1456240472.389) Received: a36c0c1a328d6ba2440d246540305400455588a54b8fdd10906502514302

[...]

Le format exact du code doit maintenant être déterminé afin de configurer rfcat, et donc la puce TI afin d'extraire uniquement les codes pertinents, sans le bruit.

Les observations dans GNU Radio, Audacity, baudline et rfcat peuvent être recoupées pour arriver à ce format supposé de codes : un octet nul, 13 octets de préambule alternant des bits à 0 et 1, un sync word valant 0xA5AA, et apparemment 27 octets de données significatives.

En tenant compte de tous les paramètres découverts lors des étapes précédentes, un script Python basé sur la rflib est écrit, afin de capturer les signaux transmis par la clé sous forme démodulée.

import time

import sys

from rflib import *

 

try:

   d = RfCat()

   d.setFreq(433920000)

   d.setMdmModulation(MOD_2FSK)

   d.setMdmDeviatn(30000)

   d.makePktFLEN(27)

   d.setMdmDRate(2000)

   d.setMdmSyncWord(0xA5AA)

   d.RFlisten()

except Exception, e:

   sys.exit("Error %s" % str(e))

 

Ce script est exécuté avant d'appuyer sur les boutons de la clé, et voici le résultat obtenu :

Entering RFlisten mode... packets arriving will be displayed on the screen

(press Enter to stop)

(1456240974.195) Received: 69666aa656959656569a55a95a66555659a69aaaa9a9a65666a6a4 | ifj.V..VV.U.ZfUVY......Vf..

(1456240976.730) Received: 6a966aa656959656569a55995599955699959656996a59a55a9598 | j.j.V..VV.U.U..V...V.jY.Z..

(1456240981.716) Received: 6a566aa656959656569a556666955559a66a566aaa696656a995a8 | jVj.V..VV.Uff.UY.jVj.ifV...

À présent il est temps de tenter le rejeu d'un paquet reçu.

D'après les spécifications de la puce Texas Instruments du YARD Stick One [TEXSPEC], aucune configuration ne permet d'avoir un octet nul devant le préambule (p. 38 de la « spec »), ni d'envoyer un préambule de 13 octets (p. 78). L'appartenance de l'octet nul au préambule, ce qui porterait sa longueur à 14 octets, n'est pas claire non plus. La puce TI ne supporte de toute façon pas davantage de préambule de 14 octets (p. 78). Deux possibilités s'offrent alors :

- soit désactiver toutes les fonctions de préambule, voire même de sync word, et rajouter ces derniers « manuellement » dans le script de rejeu ;

- soit utiliser une configuration la plus proche possible des codes observés, en espérant que ça passe.

Dans l'exemple ci-dessous, la deuxième option est choisie, avec un préambule demandé de 12 octets.

import time

import sys

from rflib import *

 

CODE="\x6a\x95\xaa\xa6\x56\x95\x96\x56\x56\x9a\x56\xa9\x66\x59\x66\xa6\x59\x59\xaa\x96\x65\x69\x69\x99\x65\x96\x64"

 

try:

   d = RfCat()

   d.setFreq(433920000)

   d.setMdmModulation(MOD_2FSK)

   d.setMdmDeviatn(30000)

   d.makePktFLEN(27)

   d.setMdmDRate(2000)

   d.setMdmSyncWord(0xA5AA)

   d.setMdmNumPreamble(MFMCFG1_NUM_PREAMBLE_12)

   d.setMaxPower()

   d.RFxmit(CODE)

except Exception, e:

   sys.exit("Error %s" % str(e))

Ce script a ouvert la voiture avec succès, une certaine souplesse dans le format et la longueur du préambule est donc acceptée par le récepteur. D'autres tests en prenant cette fois l'option de rajouter manuellement le préambule et le syncword au code à envoyer ont été réalisés avec succès.

Le YARD Stick One est un réel gain de temps par rapport à la création des graphes GNU Radio correspondants, à condition de travailler avec des fréquences et des modulations supportées par la puce Texas Instruments.

Conclusion

L'étude présentée dans cet article ne correspond pas à un scénario réel d'attaque, car il a été nécessaire d'accéder à la clé pour pouvoir enregistrer un code d'ouverture à distance de la voiture, avant de le rejouer cette fois à proximité.

En août 2015, lors de la conférence Defcon, le chercheur en sécurité Samy Kamkar démontrait un protocole d'attaque plus avancé sur les codes tournants [KAMKAR], ainsi qu'une implémentation pratique à base de petit matériel électronique à bas prix, qu'il baptise « [ROLLJAM». Son équipement effectue simultanément un brouillage de la « fenêtre de réception » de la voiture afin de l'empêcher de capter les codes, et une capture radio avec un filtre permettant d'échapper au brouillage pour « entendre » les codes émis par la clé.

L'intérêt de ce petit équipement pouvant fonctionner sur batterie étant d'introduire des scénarios pratiques, par exemple fixer le boîtier sous la voiture ciblée et revenir le récupérer plus tard, celui-ci ayant toujours en mémoire le dernier code d'ouverture valide.

On peut également citer les travaux d'Andrew Mohawk, qui implémente une attaque similaire sur son ordinateur portable, à base de clés Yard Stick One [MOHAWK].

Remerciements

L'équipe de Digital Security pour sa relecture, et particulièrement Renaud Lifchitz et Mélik Lemariey pour leur aide concernant les arcanes de GNU Radio et la démodulation.

Références

[JEEPHACK] Andy Greenberg, article Wired « Hackers Remotely Kill a Jeep on the Highway - With Me in It », juillet 2015 : http://www.wired.com/2015/07/hackers-remotely-kill-jeep-highway/

[OWNSTAR] Andy Greenberg, article Wired, « This Gadget Hacks GM Cars to Locate, Unlock, and Start Them », juillet 2015 : http://www.wired.com/2015/07/gadget-hacks-gm-cars-locate-unlock-start/

[KISBLOG] « dragorn », article « Playing with the HackRF - Keyfobs » sur le blog Kismet, août 2013 : http://blog.kismetwireless.net/2013/08/playing-with-hackrf-keyfobs.html

[DCSPIKE] Michael Ossmann, explications sur le phénomène du « DC Spike », FAQ hackrf sur GitHub : https://github.com/mossmann/hackrf/wiki/FAQ#what-is-this-big-spike-in-the-center-of-my-received-spectrum

[GRCWIKI] Auteur inconnu, explications sur les paramètres de modulation FSK, wiki de GNU Radio : http://gnuradio.org/redmine/projects/gnuradio/wiki/SignalProcessing.

[RFCATWKS] Workshop RfCat donné par Atlas à la BHUS'12 : https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/rfcat/subghzorbust-bhwkshp.pdf

[TEXSPEC] Texas Instruments, Spécification « CC1101 Low-Power Sub 1 GHz Transceiver » : http://www.ti.com/lit/ds/swrs061i/swrs061i.pdf

[KAMKAR] Samy Kamkar, Présentation à la Defcon « Drive it like you hacked it », août 2015 : http://samy.pl/defcon2015/

[ROLLJAM] Andy Greenberg, article Wired « This Hacker’s Tiny Device Unlocks Cars And Opens Garages », août 2015 : http://www.wired.com/2015/08/hackers-tiny-device-unlocks-cars-opens-garages/

[MOHAWK] Andrew Mohawk, article de blog « Bypassing Rolling Code Systems », février 2016 : http://andrewmohawk.com/2016/02/05/bypassing-rolling-code-systems/