Le challenge (readme) nous donne les commandes à utiliser avec condaSauf 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 pythonPour l'installation poetry, il faut être dans le dossier où tous les fichiers du challenge sontNouvelle phase d'installation donc avec poetryPour 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éeEt 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 ligneEt ç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 ipynbAu passage, Jupyter ne devrait jamais être en prod (vus les risques associés), même s'il propose une authentification par tokenLe 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 maintenantOn va nous expliquer, pas à pas, le fonctionnement d'un ordinateur quantiqueDans 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'affichageEn 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 tempsIdem à quelques autres endroitsNe reste alors plus qu'à kill et restart le JupyterOu, moins violent, à recharger le Notebook (voire le 'kernel') depuis l'interfaceCela 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 cibleEn 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 anglesEt on est bon pour cette première partie du challenge
Vecteurs propres
Maintenant, on cherche des vecteurs propres (eighen vectors) ce que numpy permet directementPour p2, on procède de même mais là… plouf! Ça ne va plus, les probabilités du résultat sont incorrectesJe reprends donc le code de p0 à la recherche d'une erreur, en le clarifiantToute semble parfaitement bon pour p0Je 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 correspondantQu'on peut afficherOn le transforme en étapes élémentaires (pour pouvoir le 'sérialiser' pour le serveur)On obtient le circuit qu'on doit envoyer au serveurOn refait le même circuit pour pouvoir l'envoyer proprement 'sérialisé' au serveurOn 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 exempleEt on vérifie que le circuit marche bien comme attenduPatatr… 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!