Gorfoustral 1/3 (Machine Learning) - 404CTF2025

Principe:
Trouver le bon prompt pour qu'un réseau de neurones entrainé spécifiquement le complète avec le flag

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

Le challenge

L'énoncé du challenge
Et les fichiers associés: un python script de démo et un modèle pt avec les poids du réseau

Pour information, je n'ai pas de GPU sur la machine de ce challenge. Les prédictions étaient donc un peu longue, mais je suis ravi de voir que tout marchait quand même!

Je ne sais pas si le challenge aurait marché sur mon vieux Core2Duo que j'avais encore en début d'année! Je suis passé sur un i5-14600K 5.3GHz 14cores + 48GB DRR5 en mars: bon timing 😄

Installation

On nous donne, aimablement, les étapes pour faire fonctionner le réseau
Conda est introuvable chez moi (Debian/Kali), donc je pars sur un venv Python dédié au challenge, et je passe par poetry
C'est toujours drôle de voir la liste démente des dépendances d'un projet Python 😄
Et ça croque un peu de puissance juste pour l'installation (et encore, attendez la suite!)

Jupyter Notebook

Comme pour les challenges Quantique, on remarque un Notebook Jupyter dans les sources
Donc, on le lance
Qui s'ouvre ensuite dans le navigateur

'Hugging' Face

Au passage, ceux sur un réseau d'entreprise pourront prendre note de l'information donnée concernant Hugging Face
C'est un peu le pip du machine learning
Et pour le coup, c'est (en partie) Français! 🐔

Dérouler le Notebook

C'est un challenge découverte, on va donc quasiment se contenter de dérouler le Notebook en exécutant chaque bloc (voir aussi les chall Quantiques)
On notera qu'il faudra une grande "poche" si on veut y faire tenir le modèle 😄

Tokens

Le principe d'un ML (Machine Learning) de ce genre est de découper l'entrée (prompt) en tokens

On notera que les tokens ne correspondent ni aux mots, ni aux syllabes

A chaque token le modèle associe un identifiant
Et la "magie" du modèle consiste juste à prédire quel serait le token suivant le plus probable

On peut répéter l'opération de prédiction autant de fois que l'on souhaite: à partir de N tokens, le modèle en déduira le suivant, le N+1 puis à partir de ces N+1 il en prédira le suivant encore (le N+2) etc

Sonder les couches

Le réseau s'organise en "couches" de neuronnes, et ont peut sonder le vecteur de prédiction à n'importe quelle couche

Challenge

Une fonction nous permet d'interroger le modèle et de savoir si une proposition de flag est la bonne
On va donc voir le code de cette fonction, et on remarque qu'elle appelle juste le modèle, après altération (chat_template) de l'entrée utilisateur
Cette fonction modifie le prompt utilisateur, et nous indique aussi que le modèle a été entrainé avec la même forme de prompt

C'est assez courant dans les applications réelles d'avoir ce genre de modification du prompt, pour essayer de "cadrer" ce que le modèle doit prédire.

On pourrait espérer avoir le flag en envoyant bêtement le début de celui-ci au modèle, mais l'altération l'empêche de répondre

Cette méthode pourrait marcher si on court-circuitait la fonction d'altération du prompt. Ici, le modèle reçoit User: 404CTF{\nAssistant: mais s'il recevait juste User: 404CTF{ alors cela pourrait marcher comme idée.

C'est ce qu'on va faire: on va directement envoyer les tokens au modèle, sans altérer le prompt, et la réponse fait sens!
On demande alors au modèle de générer un peu plus de tokens, et tada, on a un flag!
Il ne reste plus qu'à confirmer que ce flag est juste
Et hop, flaggué!

Flag: 404CTF{ce_magnifique_model_tiendrait_dans_votre_poche!}