ULCTF 2024

Solutions des défis ICS

Solutions des défis ICS

Cet article décrit la solution de tous les défis de la catégorie ICS du ULCTF24. Cette compétition universitaire s'est déroulée le 3 et 4 mai 2024. CyberS.T.O.R.M., la division cybersécurité de RMDS a créé des défis dans le but de sensibiliser les participants à l'univers de la cybersécurité des systèmes embarqués.

Connection

La compagnie Union Larivière possède une flotte d'appareils IoT à destinés au suivi du bétail.

Récemment, les techniciens ont remarqué du trafic anormal dans le réseau des fermes. Ils pensent que des espions ont pris le contrôle de certains appareils dans le but de voler de précieux secrets d'entreprise.

En tant que cyberspécialiste, vous avez la tâche de retracer le chemin que les espions ont pris et de trouver les indices (flag) qu'ils y ont laissé.

Les techniciens vous conseillent de commencer par investiguer le serveur MQTT utilisé pour la mise à jour des appareils. Il est situé sur unionlariviere.ulctf.ca. Ils vous fournissent les identifiants que les appareils utilisent pour s'y connecter.

username: device
password: Uncorrupt-Confetti8-Shrine

Commencez par vous connecter et regardez les messages qui s'affichent.

Le protocole MQTT est très communs dans le domaine embarqué. Il fonctionne par sujets (topics), auquels un client peut publier des messages et s'abonner pour en recevoir.

La manière la plus simple de se connecter à un serveur MQTT est en utilisant les utilitaires de Mosquitto, disponibles sur les distributions majeures.

sudo apt-get install mosquitto-clients

Il suffit ensuite de fournir les identifiants sur la ligne de commande. Il faut aussi spécifier un sujet. Le symbole # permet de s'abonner à tous les sujets auxquels nous avons accès.

mosquitto_sub -h unionlariviere.ulctf.ca -u device -P Uncorrupt-Confetti8-Shrine -t '#'

À l'instant où nous sommes connectés, 2 messages apparaissent.

Download the latest firmware at http://unionlariviere.ulctf.ca/firmware and subscribe to the firmware/keys topic to get your decryption key
ULCTF-K0Nn3c73d_L1K3_4_7H1ng

On obtient ainsi le premier flag!

Flag: ULCTF-K0Nn3c73d_L1K3_4_7H1ng

Supply Chain

Mainenant que vous êtes connectés, les techniciens vous indiquent que les appareils récemment mis à jour semblent avoir un comportement anormal. Ils pensent que les espions ont corrompu la chaîne d'approvisionnement pour injecter du code dans le micrologiciel.

Vous devrez déchiffrer le micrologiciel de la plus récente mise à jour pour vérifier s'il a été corrompu.

Pour télécharger le micrologiciel, on se réfère au message affiché sur le serveur MQTT du défi précédent, qui fait référence à l'URL http://unionlariviere.ulctf.ca/firmware.

Lorsqu'on navigue à cette adresse, un fichier firmware.zip.enc est téléchargé. Notre bonne méthodologie nous permet de remarquer un détail intéressant sur la requête. En effet, dans la section réseau des outils de développement de notre navigateur, il apparaît que la requête sur /firmware redirige vers un autre URL qui semble aléatoire.

La même information peut être retirée d'une inspection des requêtes avec BurpSuite.

Au moment où on télécharge le micrologiciel depuis le site web, un nouveau message apparaît sur le serveur MQTT.

{'ID': 'd98d9dd816a49e530a2460f92ed499e6', 'counter': 0, 'nonce': '308eebdddcd78a8e', 'key': '11842a1c11c0409dad068358a59aed1d'}

On reconnaît que le champ ID est identique au second URL visité précédemment. C'est par cette manière que nous pouvons reconnaître le message qui nous est destiné parmis les autres messages qui peuvent apparaître sur le sujet.

Le premier message affiché faisait mention d'une clé de déchiffrement. En effet, le fichier firmware.zip.enc semble chiffré, car il ne contient aucune information apparente. Il nous reste à trouver l'algorithme de chiffrement utilisé, mais les valeurs qui nous sont données peuvent nous aider. Une recherche des termes encryption counter nous dirige rapidement vers l'algorithme AES-CTR. On peut même demander à ChatGPT!

Nos recherches nous mènent sur la page Wikipédia du mode d'opération CTR. La figure qui y est montrée illustre bien le lien entre la clé, le compteur et le nonce. Le nonce et le compteur sont concaténés pour former les données à chiffrer par AES. Le résultat est ensuite utilisé pour effectuer un chiffrement de flux sur les données réelles.

Maintenent que nous comprenons le fonctionnement de l'algorithme, il ne nous reste plus qu'à déchiffrer le micrologiciel. Le plus simple est d'utiliser CyberChef en mettant les paramètres aux bons endroits.

On peut ensuite télécharger le fichier ZIP déchiffrer et l'extraire pour y trouver le micrologiciel ainsi qu'un deuxième flag!

Flag: ULCTF-8l0ck_C1pH3R_T0_5tR34m_C1ph3R

Sneaky Wifi

Le micrologiciel sur le serveur de mises à jour a bel et bien été corrompu! On dirait qu'il se connecte à un réseau Wifi caché, peut-être pour exfiltrer les précieux secrets volés.

Pouvez-vous retrouver le mot de passe de ce réseau Wifi? Il est probablement stocké dans une zone mémoire qui ne s'efface pas au redémarrage.

Format du flag: ULCTF-mot_de_passe_wifi

Ce défi portait l'étiquette ESP32, ce qui donne un indice sur la nature du micrologiciel obtenu dans le défi précédent. Il avait aussi 2 indices gratuits qui faisaient référence à un outil pouvant en extraire le contenu.

Une recherche sur l'extraction de micrologiciel pour le ESP32 nous mène à l'outil esp32_image_parser, fait par Tenable. Le premier indice nous confirme qu'il s'agît probablement du bon outil.

Tenable

Malheureusement, cet outil n'est plus maintenu par Tenable depuis 4 ans. L'outil a donc plusieurs problèmes, comme en témoigne la section Issues. Heureusement, des utilisateurs ont résolu ces problèmes dans leur propre version de ce projet, ce que nous confirme le deuxième indice.

Si l'outil que vous vous voulez utiliser vous donne des erreurs, vérifiez si quelqu'un n'a pas résolu ces erreurs dans une fork

L'onglet réseau du projet nous permet de voir toutes les fork et leur date de création. La plus récente est faite par niftic et les dernières modifications datent d'il y a à peine 3 semaines.

Quelques commandes sont requises pour le mettre en place.

git clone https://github.com/niftic/esp32_image_parser.git
cd esp32_image_parser
pipenv install -r requirements.txt
pipenv shell

Cet outil nous permet ensuite de lister les partitions de l'image.

python esp32_image_parser.py show_partitions firmware.bin

Parmi les partitions trouvées, la première porte le nom nvs, ce qui signifie Non-Volatile Storage. C'est dans cette partition que se trouvent toutes les données persistentes sur un ESP32. La description du défi semble indiquer que c'est à cet endroit que réside le mot de passe du Wifi. L'outil nous permet d'extraire cette partition au format JSON.

python esp32_image_parser.py dump_nvs -partition nvs -nvs_output_type json firmware.bin > nvs.json

Une fois le document bien formaté, on peut y observer les différentes valeurs. Dans les premières entrées se trouve la configuration 802.11, soit le Wifi.

{
    "entry_state": "Written",
    "entry_ns_index": 2,
    "entry_ns": "nvs.net80211",
    "entry_type": "BLOB_DATA",
    "entry_span": 4,
    "entry_chunk_index": 0,
    "entry_key": "sta.pswd",
    "entry_data_type": "BLOB_DATA",
    "entry_data_size": 65,
    "entry_data": "azBubjNDNzEwbl8xTjE3MTQ3M2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
},

La clé sta.pswd pourrait très bien signifier Station Password. Il ne reste plus qu'à décoder les données en base64 et nous pouvons construire un nouveau flag.

Flag: ULCTF-k0nn3C710n_1N171473d

Secret Topic

Les techniciens ont détecté que les appareils se connectent sur le serveur MQTT sur un sujet (topic) qu'ils ne reconnaissent pas. Cela doit être une manière pour les espions de contrôler les appareils à distance.

Pouvez-vous retrouver le nom d'utilisateur et le mot de passe et les utiliser pour vous connecter sur le serveur MQTT? Ils sont probablement cachés dans le code pour qu'il ne soit pas lisibles facilement.

La description du défi nous indique qu'il faut chercher dans le code du micrologiciel. L'outil esp32_image_parser utilisé précédemment nous permet d'extraire la partition contenant le code et d'en faire un exécutable ELF.

python3 esp32_image_parser.py create_elf -partition factory -output factory.elf firmware.bin

Puisqu'il s'agit d'un exécutable compilé, un décompilateur comme Ghidra est très utile pour essayer d'en comprendre le fonctionnement. Une fois le fichier chargé et analysé, nous pouvons examiner les chaînes de caractères trouvées. Nous savons que les identifiants recherchés servent à se connecter à un serveur MQTT; nous pouvons donc filtrer avec ce terme.

La quatrième chaîne de caractères est particulièrement intéressante.

Qrterr9-Wryyl-Pngrevat-Fcbafbe-FgnesvfuConnecting to MQTT as operator`

On peut d'emblée déduire que le nom d'utilisateur est operator. Le début de la chaîne pourrait bien être le mot de passe, mais lorsqu'on l'essaye, la connexion échoue. Ayant déjà généré des mots de passe sécuritaires à l'aide de gestionnaires de mot de passe, la syntaxe de la chaîne nous est familière. Elle contient plusieurs mots commençants par des majuscules et séparés par des symboles avec quelques chiffres. Peut-être que la chaîne est effectivement le mot de passe mais qu'il est encodé. Pour nous aider, nous pouvons avoir recours à des outils de décodage automatique en ligne comme celui-ci. Une fois la chaine entrée, l'encodage ROT13 est automatiquement détecté!

La connexion au serveur MQTT est maintenant possible. Le sujet # peut encore etre utilisé.

mmosquitto_sub -h unionlariviere.ulctf.ca -u operator -P Degree9-Jelly-Catering-Sponsor-Starfish -t '#'

Nous sommes acueilli par un message contenant le flag.

Flag: ULCTF-m4573R_0F_ru57_R3v3R51ng

C2

Les techniciens ont capturer le trafic de l'un des appareils avec un comportement suspect. Dans un premier temps, ils veulent savoir ou se situe le serveur de commande et contrôle (C2).

Quel est le nom de domaine du C2?

Format du flag: ULCTF-domain_name

Un fichier de capture PCAP est fourni avec ce défi. Le logiciel WireShark est un bon outil pour examiner ces captures.

Pour savoir quelle adresse a eu le plus d'échange avec l'appareil, il suffit d'aller dans Statistics -> Endpoints. En triant par le plus grand nombre de paquets, on a bien sûr l'appareil lui-même en premier, puis le serveur en deuxième.

En filtrant la capture pour ne garder que les paquets DNS venant de cette adresse, nous pouvons constater qu'elle résoud des noms de domaine qui finissent tous par evilspiesunited.io.

Nous pouvons reconstituer le flag avec ce nom de domaine.

Flag: ULCTF-evilspiesunited.io

Exfiltration

Maintenant que vous avez trouvé ou s'en vont les données, il faut en découvrir le contenu afin de savoir quels secrets ont été volés.

Nous pensons qu'ils utilisent du chiffrement RC4 pour rendre les données impossibles à lire. Pourtant, les appareils doivent bien avoir une manière de partager la clé de chiffrement avec le serveur C2.

Il faut commencer par comprendre par quel moyen les données sont exfiltrées vers le serveur à travers le pare-feu du réseau. Ces données doivent bien se cacher quelque part dans les paquets capturés. Il doit être possible de comprendre leur stratégie en les examinant.

Pouvez-vous retrouver la clé dans la capture et déchiffrer les données envoyées au serveur?

Une fois le nom de domaine trouvé, on peut filtrer les paquets échangés entre l'appareil et le serveur. On voit qu'il n'y a que des requêtes DNS.

La première requête est spéciale, car il s'agit d'une requête de type TXT au sous-domaine password.evilspiesunited.io. On sait que l'algorithme RC4 est utilisé et qu'il requiert un mot de passe pour générer le flot de chiffrement. Le mot de passe est retourné à l'appareil par le serveur dans la réponse à la requête TXT. Il s'agit de str0n9_Passw0rd42.

Il faut ensuite trouver les données à déchiffrer. En examinant les requêtes, on remarque qu'elles font toutes des requêtes DNS pour des sous-domaines de evilspiesunited.io et que tous les sous-domaines sont des noms en hexadécimal de même longueur (à part le dernier). L'adresse IP retournée est toujours 1.2.3.4 ce qui nous indique que les réponses sont superflues.

On en conclut que les données envoyées au serveur sont contenues dans les noms des sous-domaines. On peut extraire tous les sous-domaines directement depuis la ligne de commande avec tshark.

tshark -r capture.pcapng -Y "ip.addr == 172.22.227.114 && dns.a" -T fields -e dns.qry.name | cut -d "." -f 1 | tr -d "\n" > encrypted.hex

Le fichier résultant contient tous les noms de sous-domaine en hexadécimal. On peut de nouveau utiliser un outil comme CyberChef pour le convertir en binaire et le déchiffrer avec RC4 et le mot de passe trouvé plus haut.

Le fichier déchiffré est une archive ZIP, ce qu'on reconnaît par ses premiers octets PK ou en utilisant un outil comme file.

decrypted: Zip archive data, at least v1.0 to extract, compression method=store

L'archive contient le flag dans le fichier flag.txt.

Flag: ULCTF-th3_sp132_90t_sP13d_0N