Cyber on Board 2025 writeups [IoT/Hardware] 🇫🇷
Introduction
Du 14 au 15 mai 2025 avec la fine équipe nous avons eu l’occasion de représenter l’ecole 2600 en tant que Phreaks 2600 au premier CTF du cyber on board, une convention dédiée à la sécuritée des systèmes embarqués.
Le challenge avait été réalisé par neverhack et comportait deux circuits imprimés reliés entre eux. Il représentait le système d’un drone et exposait des valeurs comme l’altitude sur un petit écran. Il y a aussi d’autres composants comme un qui servait à envoyer des données sur les bus CAN, et une EEPROM qui communiquait en I²C.
Parmi le matériel fournit on avait :
- analyseur logique
- flash rom programmer
- Crochets de test reliés avec des cables dupont
- Deux cables USB vers mini-USB
- Crochets pour extraction de rom
Après un début difficle on a fini par se classer 5/13.
Challenges
Serial Killer exposed
Pour ce challenge, le titre nous indique la voie à suivre avec le “Serial”. Une communication série est la voie de communication la plus présente en hardware. C’est lorsque deux appareils communiquent directement en étant connecté avec un cable par exemple. USB est un protocole de communication série.
En se branchant en USB on peut directement se connecter à un des composants (teensy). Maintenant pour surveiller ce qu’il se passe, on peut utiliser un outil qui va directement lire ce que la teensy nous envoie avec des outils comme minicom ou screen.
En connectant le cable, en redémarrant le circuit électronique et en lançant rapidement screen /dev/ttyACM0
, on voit apparaitre des messages d’initialisation du circuit.
Puis ensuite en appuyant sur n’importe qu’elle touche on voit Unknown command
s’afficher. Donc en faisant un script pour pouvoir entrer plus de caractères, on arrive à faire afficher un menu avec la commande help
. Voici le script:
|
|
Puis les commandes dispos étaient :
|
|
En envoyant flag
on récupère : COB{FEnw3mfUFlopd_0c=MuWi_2T70C4wUeiE2o3-tHE}
.
Dumpsters
Avec le nom “dumpsters” ca n’a fait qu’un tour, on a compris qu’il fallait dump un firmware. Parmi tous les composants, un seul correspondait à une ROM qui pouvait contenir un firmware :
La référence dessus est 24LC512 I/P RVD 2019. Après une courte recherche on tombe sur une datahseet du fabricant MICROCHIP : https://www.alldatasheet.fr/datasheet-pdf/download/348628/MICROCHIP/24LC512.html.
Il s’agirait donc d’une EEPROM (Electrically Erasable Programmable Read-Only Memory), pour faire court, une puce qui sert de stockage persistant. Le protocole utilisé par la puce est I²C.
A partir de ce moment on a tenté de ce brancher à la puce avec des cables pour extraire le firmware avec flashrom
et le programmeur flash CH341A mais ca passait pas. Après un long moment de galère, on nous a indiqué que les puces n’étaient pas soudées donc on pouvait les retirer et on a tenté avec un autre outil IMSProg et c’est passé.
Toutes les infos étaient sur la datasheet, et en cherchant “COB{” dans la donnée extraite, on trouve le flag
COB{U:gtxv4HPEruC2rg1Fxl7TfSiQmJmI_=FXKw:QAH}
.
CAN u replay it
L’objectif du challenge est de faire en sorte que les valeurs affichées sur l’écran soient toutes à 0 pendant 10 secondes.
Dans son comportement normal, l’écran diffuse des informations mises à jour tout les demi secondes comme par exemple l’altitude du drone qui varie quand on souleve la board :
Ces valeurs sont transmises, par différents éléments, il y a la carte teensy
ainsi qu’un module MCP2515
couplé au module MCP2551
qui permettent d’en envoyer. Mais la carte teensy
est directement reliée au MCP2515
donc on suppose qu’elle est là car on peut la programmer (voir le challenge serial killer exposed).
Maintenant l’objectif était de savoir quelles valeurs rejouer pour pouvoir tout mettre à zéro.
Pour commencer on a du observer les paquets envoyés durant le comportement normal du drone..
En connectant un crochet de test sur CANH, un sur CANL et sur GND, on a pu observer des données transiter sur l’analyseur logique (saleae logic 2).
Mais aucune donnée n’était compréhensible. (J’ai pas de captures d’écran malheureusement.)
Ce qu’il se passe était que notre outil était réglé sur le mauvais baudrate (ou bitrate). C’est-à-dire la fréquence de bits reçu par secondes. Le circuit est programmé à en envoyer sur une certaine fréquence mais si nous de notre coté on en utilise une différente, les données seront illisibles car on reçoit les données à une fréquence différente que celle effective.
Pour trouver le bon baudrate il y a deux choix :
- la méthode naïve : on tatonne jusqu’à trouver le bon baudrate
- la méthode datasheet : on utilise le baudrate par défaut définie dans la datasheet
- la méthode smart : on prend l’impulsion avec la période
T
la plus faible dans la capture, et de faire le calcul : $\frac{1}{T}$. Dans notre cas, sur l’analyseur logique on a T = 8 microsecodes = 0.000008 secondes. Donc $\frac{1}{T} = 125000$ Hz. Et ainsi on a notre baudrate.
Maintenant qu’on a notre baudrate les données sont lisibles et on voit que le meme type de paquets CAN sont envoyés en boucle.
Il fallait garder les valeurs qui ne bougent pas dans les paquets et mettre des zéros pour celles qui varient.
Sauf que, le drone continue à avoir ses valeurs qui se mettent à jour donc ça nous empechait de tout mettre à zéro. Il y avait une commande intéressante durant le challenge serial killer exposed qui était gyro_stop_update
. En faisant ça, il n’y a plus rien qui s’envoie sauf nous paquets à nous, on peut ainsi envoyer plein des paquets avec zéro comme valeur en boucle :
|
|
Et on récupère le flag :
COB{uAGm9f2:mAEEzPIX7L3T}
CAN u sniff it
Pour ce challenge là on devait intéragir avec une commande secrète. Et la seule ocmmande secrete qu’on avait était la commande secret
du challenge serial killer exposed.
En activant la commande on nous demande un mot de passe et ensuite ce-dernier est vérifié.
En regardant sur l’analyseur logique ce qu’il se passe au niveau du CAN bus, on voit d’avantage de choses:
On reçoit toujours trois paquets, un remplit de 0xff
, et deux autres avec des caractères ascii imprimables.
En tâtonnant on comprend qu’il faut concaténer les 5 derniers caractères : rvNdRm86YW. Et en renvoyant ça on obtient le flag.