Prologue

Étape 0 - prologue

Description

The year is 2022. Gunshots shattered the night. A witness caught a glimpse of a vehicle at the scene — a Tesla, they claim? The investigators on the case firmly believe this incident is affiliated with a clandestine criminal group that has eluded them for years... You are given the police reports and a backup of the car's logs. Your technical expertise is needed to move the investigation forward!

Download the challenge files (sha256: e95deeb7202cc10786f767f83644291bd76958d86e2d311c4e93efade85b75cd)

Your are mandated to conduct an investigation on this group and ultimately retrieve a validation e-mail ([0-9a-f]{16}@sstic.org).

Indice

Un indice a été donné quelques jours après la parution de l’épreuve :

Important advice regarding the prologue: don't overthink it! Just carefully read the elements you are given — these clearly suggest what you should look for in the context of the investigation. As mentioned right above, an intermediate flag can be found after you solved the prologue; you are not necessarily looking for a SSTIC-formatted flag right away. Immerse yourself and try to answer what you're asked!

Résolution

Aussi appelée pas loin d’abandonner dès le début. Le lecteur qui ne désire pas s’encombrer des échecs successifs peut directement sauter à la section Finalement.

Setup

Le lien de téléchargement fourni contient les données suivantes :

Les deux fichiers PDF sont des éléments récoltés par la police en Belgique pour tenter d’élucider un crime survenu en août 2022. Le premier retranscrit un entretien de témoin ayant assisté à la scène et déclarant avoir vu une Tesla blanche au moment de l’événement. Le second fournit la justification du fichier de backup obtenu, en montrant l’ordre de communiquer le fichier de backup aux autorités mandatées (de la “seule Tesla blanche” à proximité au moment du crime).

TeslaMate est OpenSource et facilement installable en suivant les instructions indiquées.

Le docker-compose fourni expose 4 services incluant une base de données postgreSQL, un Grafana pour visualiser les données, une interface Web en Elixir qui fait à peu près la même chose (et redirige sur le Grafana pour la plupart des requêtes et dashboards) mais permet des actions sur les paramètres ou sur la Tesla elle-même (a priori). Le dernier service est un broker MQTT pour supporter le transport des messages, de peu d’intérêt ici.

On peut facilement importer les données de la backup qui sont un export SQL classique, la procédure est d’ailleurs documentée sur le site officiel :

docker-compose exec -T database psql -U teslamate -d teslamate < teslamate.bck

Exploration initiale

Une fois la DB en place, on peut constater qu’il y a peu de tables accessibles, et se dire que ça ne devrait pas être trop difficile de trouver les données qui nous intéressent (erreur) :

13 tables déclarées en DB

L’oeil avisé aura reconnu un étrange “http_” dans le nom de la première geofence. L’oeil non avisé n’aura pas prêté attention à ce détail, ce qui va lui coûter cher en heures par la suite

Avant d’entrer dans le détail du contenu de la DB, on peut également aller fouiller sur le Grafana. Étant donné qu’on semble nous indiquer d’aller chercher les habitudes de conduite de notre suspect principal, on peut directement aller au dashboard associé :

Des stats intéressantes mais pas de flag a priori

Parmi tous les dashboards proposés, on peut en trouver un qui récapitule les trajets du suspect, notamment vers la date du crime :

Un parcours bien singulier
Avec les destinations affichées, le fameux lieu-dit camouflagepad

Sur le parcours affiché, on peut constater une anomalie suspecte qui correspond en plus au jour du drame :

On zoome on zoome on zoome, on va peut être voir euh …

Finalement, ça ne donne rien de probant (en même temps, qu’est-ce qu’on s’attendait à trouver en zoomant sur l’anomalie …). Aucun des autres dashboards ne semble aboutir à l’affichage de données pertinentes.

Retour à la donnée brute

Puisque les différents dashboards Grafana ne révèlent rien au premier regard, il est temps de regarder les tables qui sont potentiellement en lien avec des localisations. Parmi celles-ci, on retrouve :

Intéressons nous à la table adresses. Celle-ci contient 83 enregistrements, chacun étant composé d’au moins un nom, le résultat d’une requête OpenStreetMap (OSM) et d’un OSM_ID :

Extrait de la table adresses avec les champs name, raw et osm_id

Les données de longitude et latitude indiquées sont cohérentes avec celles de la colonne raw :

La longitude et latitude indiquées dans le raw json sont OK

Cependant, certaines anomalies viennent perturber la cohérence des données, et notamment des noms de lieux inexistants:

Noms de lieu inexistants, camouflagepad, qui aurait pu deviner ?

Est-ce que notre auteur sur OpenStreetMap est de confiance ?

Let’s dig to nowhere

De plus, les OSM_ID indiqués dans la dernière colonne ne sont pas cohérents par rapport à ceux du JSON. On peut faire la corrélation avec OpenStreetMap.

Peut-être notre bonheur dans une metadonnée ??

Finalement, la piste se révèle infructueuse.

Le moment de se perdre

On revient aux dahsboards, et comme on commence à manquer d’idées, on va entamer une phase d’hallucination individuelle consistant à voir du binaire partout où il y en a, mais pas pour former un flag :

Et pourquoi pas dans la consommation de la batterie ?
Encore du binaire, ça ressemble pourtant non ?

Finalement, au bout de plus de 130 cases d’un notebook Jupyter sans sens :

On y est, c’était ça … non toujours pas

NDLR : Généralement, sortir numpy pour calculer des LSB sur des données obscures, alors que l’épreuve a été déjà flag en moins d’une heure, est une (très) mauvaise idée.

Plus à ça près

Après un retour à la base de données, on se rend compte qu’il y a une table tokens qui contient une unique ligne, avec ce qui semble être un access et un refresh token chiffrés. BINGO ! D’après la documentation, ces éléments sont chiffrés avec le mot de passe qui est demandé lors de l’accès à l’API Tesla depuis teslamate.

Qu’à cela ne tienne, on va tenter cette piste prometteuse. Encore faut-il savoir comment est chiffré le jeton et de quel jeton il s’agit. Pour cela, il faut créer un compte sur le site de Tesla pour obtenir un access token valide :

Création d’un compte Tesla

On peut ensuite s’authentifier en local à l’aide du binaire tesla_auth qui ouvre un mire d’authentification. Une fois connecté, on obtient les jetons espérés, qu’on peut transmettre à l’application teslamate :

Utilisatino du compte créé pour la génération d’un access et d’un refresh token

Au final, ces jetons sont chiffrés avec le mot de passe choisi initialement dans la configuration du docker-compose ( variable d’environnement ENCRYPTION_KEY). Le mécanisme de chiffrement choisi peut être retrouvé dans le code source Elixir du fichier vault

Un chiffrement et un format réalistes

Quelques lignes de python plus tard et on constate qu’on récupère bien le JWT pour la clé valant le secret par défaut. On tente donc un script de bruteforce du secret sur le jeton initial, le mot de passe sera dans rockyou non ?

Let’s BF this

Encore raté …

Finalement

Rien de tout ça n’était nécessaire au final. L’indication du pdf suivante couplée à la visualisation via le Grafana étaient les seuls éléments utiles à la résolution du prologue :

WOULD YOU HAPPEN TO KNOW WHERE THIS CAR USUALLY WENT? FOR INSTANCE, ITS MOST VISITED PLACES. SUCH INFORMATION WOULD HELP IN OUR INVESTIGATION

Le grafana présente en effet une vue Drive Stats qui montre ce qu’on cherche, à savoir les lieux les plus visités par le suspect / coupable :

Eh oui, tout était accessible sans (presque) rien faire

On se rend sur http://163.172.99.233:8080 et c’est gagné pour cette step 0, pfiou :

curl http://163.172.99.233:8080 2>&1|grep SSTIC\{
  ...SSTIC{0a3ef4d4bb265ca2f27dd557be0...}

Analyse post-mortem

Bien que certains spécialistes en stéganographie et en analyses des petits détails aient immédiatement su comment exploiter les données atypiques contenues dans la base TeslaMate, le problème est qu’ici il y a beaucoup d’éléments de contexte et de données qui peuvent être interprétés comme autant de pistes potentielles infructueuses.

Certaines incohérences ou anomalies (comme la singularité du trajet au moment de l’accident affichée sur Grafana, les différences entre OSM ID entre raw json et colonne de la table adresses, ou bien encore le manque de certains identifiants auto-incrémentés dans la table des drives) poussent naturellement à creuser de manière futile des culs-de-sac.

Même s’il s’agit d’un reproche qui est facile à faire vis-à-vis de la stéganographie de manière générale, il n’en demeure pas moins une certaine frustration engendrée à passer plus de 6 heures sur un tel début. Malgré tout, le cheminement proposé reste “logique”, seulement le résultat est caché de manière complètement irréaliste dans un flot de données qui le sont beaucoup plus.

Bref, la partie du challenge que j’ai le moins appréciée (il en faut bien une), merci à la personne qui m’a donné le coup de pouce / remis sur les bons rails pour franchir cette étape.