Renseignez-vous sur le matos de votre cible

Comme à mon habitude au sein d’ACCEIS, je suis arrivé le matin avec l’idée en tête de nouer des relations encore meilleures avec mes collègues.

En déambulant, mon œil a naturellement été guidé vers un bureau vide avec la porte grande ouverte. Porté à la fois par une part importante de curiosité ainsi que part une irrésistible envie de faire une connerie, je me suis introduit sans plus attendre dans le bureau.

Aucun ordinateur n’étant présent, j’ai donc abandonné la possibilité d’un croissantage pour le lendemain, cependant j’ai rapidement aperçu un casque audio muni d’une base que je ne connaissais pas. Par ailleurs, son fonctionnement ne m’a pas paru conventionnel.

Après avoir pris quelques photos pour obtenir les caractéristiques de base, je suis revenu à mon bureau et j’ai commencé à me renseigner plus en détail sur la marque et le modèle de ce casque.

Après avoir réussi à trouver la référence du produit, je me suis rendu compte d’une caractéristique importante. Le casque audio en question fonctionne sur de la radio fréquence (RF). C’est le modèle RS 120 II de la marque Sennheiser, le produit est décrit comme étant un ensemble émetteur UHF et casque sans fil. La base se branche en Jack et re-diffuse le signal reçu sur une modulation FM.

La fiche technique du casque nous apprend plusieurs caractéristiques importantes :

  1. La base à une portée totale de 100 mètres
  2. Modulation FM Stéréo
  3. Gamme de fréquences UHF : 863 à 865 MHz

Les spécifications trouvées correspondent à celles affichées sur la base.

La gamme de fréquence correspond à une plage RF dans la catégorie des UHF réservées aux “microphones sans fil” (863 à 865 MHz).

Commencez l’espionnage

D’après les renseignements précédemment récupérés, la gamme de fréquence d’émission de la base est comprise entre 863 et 865 MHz.

Pourquoi ne pas essayer d’écouter sur celle-ci ?

J’ai donc cherché dans la réserve d’ACCEIS aussi appelée No man’s land.

Après moultes péripéties, j’ai enfin trouvé une boîte pouvant contenir ce que je cherche. Ainsi qu’une casquette de capitaine plutôt chouette.

Grâce à la magie de Noël et à l’aide du père Noël, je suis tombé sur un magnifique BladeRF A4 Full-Duplex avec deux antennes RX et deux antennes TX. 

C’est maintenant que les choses intéressantes vont commencer.

Après une installation somme toute assez rapide :

sudo add-apt-repository ppa:nuandllc/bladerf
sudo apt update
sudo apt install -y bladerf
sudo apt-get install bladerf-fpga-hostedxa4   # for bladeRF 2.0 Micro A4

Une mise à jour du firmware :

bladeRF-cli --flash-firmware /usr/share/Nuand/bladeRF/bladeRF_fw.img

Et l’upload du FPGA :

bladeRF-cli -l /usr/share/Nuand/bladeRF/hostedxA4.rbf

Il ne me reste plus qu’à le calibrer :

$ bladeRF-cli -i 
bladeRF> cal dc rx 
RX DC I: Value = -1984, Error = 2.053 
RX DC Q: Value = -1824, Error = 12.256

Tout est prêt du point de vue du BladeRF, maintenant pour l’écoute, je vais utiliser gqrx qui est un SDR open source.

Une petite installation :

sudo apt install -y gqrx-sdr

Démarrons notre espionnage en bonne et due forme. D’après les specs techniques, on sait que l’émetteur émet sur une fréquence (qui peut varier) entre 863 et 865 MHz.

Nous trouvons le signal audio sur la fréquence 863.348 MHz.

Comme il est possible de l’entendre sur cet enregistrement, notre cible écoute des musiques d’un goût… assez particulier. En tout état de cause, un redressement culturel s’impose. 

Après un peu plus de recherche, je m’aperçois que le signal est visible sur d’autres harmoniques, sur des fréquences différentes qui sortent de l’intervalle donné par le constructeur, et de l’intervalle réglementaire pour ce type d’usage.

La première harmonique se trouve sur la fréquence 172.801MHz.

Après un peu plus de recherche, on observe la présence d’harmoniques dans les très Hautes Fréquences (288.657 MHz).

C’est une fréquence réservée à plusieurs utilisations notamment liées au spatial, à l’aéronautique et au domaine militaire.

Les bandes 225,000 à 400,000 MHz sont indiquées comme étant réservées pour : l’aéronautique UHF, liaisons satellitaires, militaires, ACROPOL et celles comprises entre 225 MHz à 326,5 MHz sont dédiées à l’aéronautique UHF militaire, contrôle espace aérien supérieur, service aérospatial.

S’il est vrai que changer les goûts musicaux de ses collègues peut se révéler utile, participer à la rééducation musicale d’un pilote de chasse est une perspective beaucoup plus intéressante. Pour peu qu’il passe au-dessus du bâtiment (rayon 100 mètres), nous aurons ainsi tout le loisir de lui envoyer quelques notes de musique pour les quelques secondes de survol.

Injectez 2, 3 répliques de film durant une conf call

Nous pouvons espionner notre collègue, maintenant il serait intéressant de savoir si l’émission sur cette même fréquence permet d’injecter de l’audio sur le casque.

Le plus simple (enfin tout est relatif) c’est d’installer gnuradio et de construire un programme prenant en entrée un fichier audio (voire un micro) puis d’effectuer les modulations permettant l’envoi en FM.

Donc pour l’installation, un simple :

sudo apt install gnuradio

Maintenant, il ne nous reste plus qu’à construire le programme. 

Après quelques recherches, afin de moduler un fichier wav en fm, il suffit d’encoder notre source avec du CVSD et d’appliquer une modulation GSMK.

CVSD ou Continuously Slope Delta Modulation est une méthode d’encodage de la voix.

GMSK ou Gaussian Minimum Shift Keying est une modulation remplaçant les impulsions rectangulaires par des impulsions gaussiennes.

Il ne reste qu’à tout mettre ensemble sur gnuradio.

Pour notre audio, je vais utiliser le bloc Wav File Source (mais il est aussi possible de choisir le bloc lié au micro). Le flux audio est encodé en CVSD avec un échantillonnage de 8 et une Bandwidth de 500m. Je le module ensuite en GMSK et l’envoie à la sortie dans le bloc d’émission du BladeRF. 

Afin de rendre les variables configurables, j’ajoute des blocs GUI. Ils vont nous créer des éléments graphiques permettant de modifier nos variables pendant l’exécution du programme. 

Programme final avec bloc graphique

Les GUI Range affichent des curseurs et Sink affiche en temps réel le flux.

Il ne reste plus qu’à télécharger des répliques du Grand Détournement pour les envoyer sur le casque de notre cher collègue.

Maintenant arrive l’heure du test.

Tout fonctionne à merveille !

Finissez par une rééducation de leurs goûts musicaux

Notre fabuleux programme en bloc Gnu_Radio fonctionne parfaitement, mais il est un peu contraignant à utiliser, c’est pourquoi, je vais l’exporter en python afin, je ne sais pas, de le faire tourner sur un raspberry…

Rien de plus simple.

Il suffit de se rendre dans l’onglet Run puis Generate et nous obtenons en sortie notre fichier en python.

[bladeRF sink] bladerf_sink_c: DEBUG: initialization complete
[bladeRF sink] start: DEBUG: starting sink
[bladeRF sink] stop: DEBUG: stopping sink
>>> Done
Generating: '/home/remi/Tools/SDR/Gnu_Radio/top_block.py'

Maintenant, il nous est possible de le modifier afin de passer des extraits des artistes les plus prolifiques de notre temps. Rihanna, Cindy Sander, Keen’V, les possibilités sont infinies. A ne pas oublier, le programme est également portable, il suffit de brancher notre BladeRF sur un raspberry, d’installer les packages précédents et le tour est joué. 

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#
# SPDX-License-Identifier: GPL-3.0
#
# GNU Radio Python Flow Graph
# Title: Top Block
# GNU Radio version: 3.8.2.0

from gnuradio import blocks
from gnuradio import digital
from gnuradio import gr
from gnuradio.filter import firdes
import sys
import signal
import os
import random
from argparse import ArgumentParser
from gnuradio.eng_arg import eng_float, intx
from gnuradio import eng_notation
from gnuradio import vocoder
import osmosdr
import time

class top_block(gr.top_block):

   def __init__(self):
       gr.top_block.__init__(self, "Top Block")

       ##################################################
       # Variables
       ##################################################
       self.Bandwidth = Bandwidth = 20000000

       ##################################################
       # Blocks
       ##################################################
       self.vocoder_cvsd_encode_fb_0 = vocoder.cvsd_encode_fb(8,0.5)
       self.osmosdr_sink_0 = osmosdr.sink(
           args="numchan=" + str(1) + " " + ''
       )
       self.osmosdr_sink_0.set_time_now(osmosdr.time_spec_t(time.time()), osmosdr.ALL_MBOARDS)
       self.osmosdr_sink_0.set_sample_rate(686000)
       self.osmosdr_sink_0.set_center_freq(863346000, 0)
       #self.osmosdr_sink_0.set_center_freq(104700000, 0)
       self.osmosdr_sink_0.set_freq_corr(0, 0)
       self.osmosdr_sink_0.set_gain(100, 0)
       self.osmosdr_sink_0.set_if_gain(15, 0)
       self.osmosdr_sink_0.set_bb_gain(15, 0)
       self.osmosdr_sink_0.set_antenna('TX2', 0)
       self.osmosdr_sink_0.set_bandwidth(20000, 0)
       self.digital_gmsk_mod_0 = digital.gmsk_mod(
           samples_per_symbol=2,
           bt=0.1,
           verbose=False,
           log=False)
       self.blocks_wavfile_source_0_0 = blocks.wavfile_source('./Top_Rihanna/' + random.choice(os.listdir("./Top_Rihanna/")), False)
       self.blocks_multiply_const_vxx_1 = blocks.multiply_const_cc(1)

       ##################################################
       # Connections
       ##################################################
       self.connect((self.blocks_multiply_const_vxx_1, 0), (self.osmosdr_sink_0, 0))
       self.connect((self.blocks_wavfile_source_0_0, 0), (self.vocoder_cvsd_encode_fb_0, 0))
       self.connect((self.digital_gmsk_mod_0, 0), (self.blocks_multiply_const_vxx_1, 0))
       self.connect((self.vocoder_cvsd_encode_fb_0, 0), (self.digital_gmsk_mod_0, 0))

   def get_Bandwidth(self):
       return self.Bandwidth

   def set_Bandwidth(self, Bandwidth):
       self.Bandwidth = Bandwidth

def main(top_block_cls=top_block, options=None):
   tb = top_block_cls()

   def sig_handler(sig=None, frame=None):
       tb.stop()
       tb.wait()

   signal.signal(signal.SIGINT, sig_handler)
   signal.signal(signal.SIGTERM, sig_handler)

   tb.start()

   try:
       input('Press Enter to quit \n')
   except:
       pass
   tb.stop()
   tb.wait()

if __name__ == '__main__':
   main()

Vous voilà maintenant prêt à entamer une rééducation des goûts musicaux de vos collègues !

Conclusion (Amélioration de leurs goûts musicaux  ?)

Avant de conclure, il est clair que ce fut une fructueuse journée de travail !

En définitive, l’utilisation d’un casque RF au travail peut se révéler être à double tranchant, sauf si vous êtes ouvert à ce que vos collègues puissent entendre ce que vous écoutez et vous faire écouter n’importe quelle playlist.

Ce casque présente visiblement des défauts de conception, en particulier à cause de la présence d’harmoniques sur des fréquences d’émission non standards. Il est également possible d’émettre sur le casque même lorsque la base est débranchée.

N’importe qui, dans un rayon de ~100 mètres, peut vous écouter à votre insu en faisant de l’écoute passive.

Attention à ce que vous achetez 😉

À propos de l’auteur

Article et présentation rédigés par Rémi ASSIDI, apprenti auditeur sécurité chez ACCEIS.