Machinerie Quantique (Quantique) - 404CTF2025

Principe:
Installer l'environnement et découvrir le monde quantique via Python

Infos (cf menu latéral):
🚩 Flaggué! +100 points gagnés — 💾 Téléchargez les fichiers du challenge
404CTF{uN3_SUp3rp0s1tIon_d3_dr4pE4ux_PoUr_1_m3l4nGE_ExPl0S1f}

Le challenge

L'énoncé du challenge

Installer l'environnement

Le challenge (readme) nous donne les commandes à utiliser avec conda
Sauf que conda, j'ai pas, et il n'est pas dispo sur Kali (ce qui m'avait posé des soucis pour installer SageMaths d'ailleurs)
Alors, on prend l'autre méthode et on passe par les environnements virtuels python
Pour l'installation poetry, il faut être dans le dossier où tous les fichiers du challenge sont
Nouvelle phase d'installation donc avec poetry
Pour ma part, poetry a voulu me demander mon mot de passe admin: j'ai dit non!

Je ne voyais aucune raison pour laquelle ce mot de passe serait utile, vu que tout se passe théoriquement dans un environnement virtuel. Donc, j'ai refusé de le donner pour éviter le risque de pourrir ma machine.

Version Python

Au passage, et pour éviter les mauvaises surprises, on prend note de la version Python demandée
Et on la compare à celle installée: c'est bon!

Je ne sais pas trop comment j'aurai fait si la version n'était pas la bonne… Je n'aurai sûrement pas installé une VM et encore moins une autre version de Python directement dans ma machine (trop de contraintes), dont j'aurai sûrement bidouillé le challenge pour qu'il passe quand même!

Pour lancer le notebook, j'avais trouvé une commande simple en ligne
Et ça se lance. Jupyter est en fait un serveur local…
… auquel on accède avec le navigateur (qui se lance tout seul). On y retrouve notre script ipynb
Au passage, Jupyter ne devrait jamais être en prod (vus les risques associés), même s'il propose une authentification par token
Le token est en effet donné dans la ligne de commande, et pourrait se retrouver dans des logs

Il existe d'ailleurs des CTF et des labs qui exploitent ce pivot. Si vous trouvez un Jupyter dans un tel contexte (ou en pentest), essayez d'en trouver le token sur la machine (dans les logs souvent). À partir de là, si vous arrivez à accéder au Jupyter, le token devrait passer et vous aurez donc une RCE (un shell en fait) directement via Jupyter!

Notebook

Lançons le notebook depuis le navigateur maintenant
On va nous expliquer, pas à pas, le fonctionnement d'un ordinateur quantique
Dans un Notebook, chaque bloc peut être un affichage ou un bloc d'exécution Python, mais le premier est étrange: il n'affiche aucun retour!

Output manquant

Rapidement, le problème de l'absence d'affichage de l'output s'est répété…
Dans certains cas, une sortie était pourtant bien affichée!
En allant voir le code Python lui-même, on remarque un switch case pour l'affichage
En cherchant la documentation en ligne, on confirme qu'il existe plusieurs moteurs de rendus. L'absence d'output doit donc être un paquet manquant.
Par simplicité, je me suis contenté de l'affichage texte dans un premier temps
Idem à quelques autres endroits
Ne reste alors plus qu'à kill et restart le Jupyter
Ou, moins violent, à recharger le Notebook (voire le 'kernel') depuis l'interface
Cela permit, au final, d'arriver à un rendu, soit graphique …
… soit texte

Un exemple des raisons pour lesquels je n'aime si peu Python… Le moindre truc a tellement de dépendances et de tentacules qu'il devient fragile, instable et galère à faire marcher.

A nous de jouer

On nous demande donc, partant d'un qbit donné, de le manipuler pour le mettre dans un état cible
En cherchant en ligne, je trouve un moyen de fixier directement les coefficients du qbit, alors, j'essaie… loupé!
J'ai, en fait, tout simplement oublié que la probabilité est le carré des coefficiens du vecteuyr quantique!
En fixant les coefficients à la racine carrée des probabilités demandées, là, on est bon.
Mais patatra: quand on essaie d'envoyer cela au serveur, on ne peut pas!

On va donc devoir utiliser les outils proposés par le challenge lui-même, et donc, de la trigonométrie pour fixer les bons angles.

Avec un peu de trigo (ou de mémoire, si on se rappelle des valeurs trigo usuelles!) on trouve les bons angles
Et on est bon pour cette première partie du challenge

Vecteurs propres

Maintenant, on cherche des vecteurs propres (eighen vectors) ce que numpy permet directement
Pour p2, on procède de même mais là… plouf! Ça ne va plus, les probabilités du résultat sont incorrectes
Je reprends donc le code de p0 à la recherche d'une erreur, en le clarifiant
Toute semble parfaitement bon pour p0
Je prends le même code sur p2 et je vois qu'il y a des erreurs: pourquoi donc?!
Et c'est là qu'entrent en jeu les… 'subtilités' Pythonesques (en toute objectivité d'amateur PHP 🙂)
On fixe le code (ça m'avait un peu agacé de perdre des heures en ayant la bonne solution mais que l'implémentation soit contre-intuitive)
Et fatalement, ça se passe mieux!

Le problème ne s'est pas posé sur p0 car la matrice des vecteurs propres devait être sa propre transposée. Donc, dans ce genre de cas, lire la matrice en ligne (comme attendu) ou en colonne (mon erreur) donne le même résultat.

Il nous reste à créer le circuit correspondant
Qu'on peut afficher
On le transforme en étapes élémentaires (pour pouvoir le 'sérialiser' pour le serveur)
On obtient le circuit qu'on doit envoyer au serveur
On refait le même circuit pour pouvoir l'envoyer proprement 'sérialisé' au serveur
On vérifie qu'on a bien le même circuit visuel, histoire de ne pas mélanger l'ordre des paramètres (des angles) par exemple
Et on vérifie que le circuit marche bien comme attendu
Patatr… ah, non, Parfait! C'est juste l'ordre d'affichage qui n'est pas identique entre la sortie du circuit et le résultat souhaité
On envoie ça au serveur et on obtient le drapeau!

Flag: 404CTF{uN3_SUp3rp0s1tIon_d3_dr4pE4ux_PoUr_1_m3l4nGE_ExPl0S1f}