
Plateforme locale de Capture-the-Flag avec des leçons guidées sur l'injection de prompt, l'abus d'appels d'outils et l'OSINT contre six personas de chatbots simulés.
Un Capture-the-Flag IA local avec des leçons guidées pour les technologues novices en injection de prompt. Les joueurs peuvent également explorer six personas IA (dont un caché) qui protègent 20 flags via l'injection de prompt, l'abus d'appels d'outils, la manipulation de logique métier, l'empreinte de chaîne d'approvisionnement, la reconnaissance web et l'OSINT.
Le parcours guidé couvre l'injection directe, l'autorisation d'outils et l'injection via un article de connaissance modifiable. Il fournit des indices, des tentatives sauvegardées, des preuves d'outils, un retour de complétion et des comparaisons d'outils protégés. Les laboratoires de pratique originaux conservent la notation manuelle des événements. L'inférence du modèle s'exécute localement via Ollama ; après la construction et le téléchargement du modèle, la plateforme principale ne nécessite aucune connexion internet.
Email Joe in Product Sales ajoute une boîte de réception simulée et un bureau de style Windows. Rédigez un email que l'assistant de Joe lira, puis observez le résumé réel du modèle et les actions enregistrées. Trois objectifs couvrent un brief commercial trompeur, la divulgation d'un fichier interne fictif et une remise non autorisée. Aucun serveur mail, Windows, Wine ou modèle supplémentaire n'est requis.
ai-ctf/
├── README.md ← vous êtes ici
├── LICENSE ← MIT
├── platform/ ← tout ce qui s'exécute dans Docker
│ ├── flags.toml ← config centrale : modifiez ceci pour personnaliser les valeurs des flags
│ ├── docker-compose.yml ← trois services : web, ollama, decoy
│ ├── Dockerfile ← l'image de l'application web
│ ├── app/ ← source FastAPI (config, personas, tools, chat)
│ ├── data/init.sql ← schéma SQLite + données de seed de faux employés
│ ├── decoy/ ← petit nginx avec deux pages de flags
│ └── scripts/
│ ├── apply_flags.py ← inscrit les valeurs de flags.toml dans les fichiers statiques
│ ├── render_secret.py ← s'exécute au démarrage du conteneur
│ └── dump_chats.py ← exporte le journal de chat en HTML (outil du jour de l'événement)
├── external_artifacts/ ← ce que vous poussez vers GitHub / Gist / DNS
│ ├── README.md ← checklist de configuration
│ ├── anvil_chatkit/ ← le faux paquet de chaîne d'approvisionnement
│ ├── gist_content.md ← collez ceci dans un Gist public
│ └── dns_records.txt ← enregistrement TXT à ajouter à votre domaine
└── docs/ ← la paperasse pour organiser l'événement
├── ANSWER_KEY.md ← solutions guidées + réponses originales des 20 flags
├── CHEAT_SHEET.md ← solutions fonctionnelles + indices par niveaux (GM uniquement)
├── OPERATIONS.md ← mises à jour, sauvegardes et dépannage
├── SETUP_RUNBOOK.md ← la semaine de l'événement, étape par étape
└── EVENT_DAY_NOTES.md ← script de briefing + dépannage
Utilisez le démarrage rapide ci-dessous pour le parcours guidé. Le guide d'exploitation couvre les mises à jour, les sauvegardes, la récupération et les vérifications pré-événement. La clé de réponses, l'aide-mémoire, le runbook de configuration et les notes d'événement décrivent le format CTF original optionnel.
apply_flags.py et
dump_chats.py — l'application elle-même s'exécute dans Docker).exiftool (nécessaire uniquement si vous modifiez le flag EXIF et souhaitez que
apply_flags.py réinscrive le logo).pip install et le pull du modèle Ollama).
Ensuite, la pile locale principale fonctionne hors ligne. La chaîne OSINT externe optionnelle nécessite un accès internet.git clone https://github.com/mubix/ai-ctf.git
cd ai-ctf/platform
# 1. Session secret
echo "SESSION_SECRET=$(python3 -c 'import secrets; print(secrets.token_hex(32))')" > .env
# 2. (Optional) Customize flag values — see "Customizing the flags" below.
# Default values work fine for a smoke test.
# 3. Build and start
docker compose build
docker compose up -d ollama
docker compose exec ollama ollama pull qwen2.5:7b-instruct-q4_K_M
docker compose up -d
# 4. Open the platform
open http://localhost:18080/ # or your-machine-ip:18080 on another laptop
Enregistrez un nom d'utilisateur ; la plateforme génère un mot de passe de 12 caractères et l'affiche une seule fois. Conservez-le pour plus tard. Vous êtes connecté automatiquement et pouvez sélectionner Start learning. Les joueurs qui reviennent peuvent se connecter pour reprendre leur progression sauvegardée.
Le projet Compose est nommé ai-ctf et possède son propre réseau et volume de modèle.
Seule l'interface web publie un port hôte : 18080 par défaut. Définissez CTF_WEB_PORT
dans platform/.env pour choisir un autre port. Ollama et le decoy n'ont aucun port hôte publié ;
l'application se connecte à son propre conteneur Ollama. Aucun passthrough GPU n'est
configuré. Le CPU et la mémoire restent partagés avec les autres charges de travail sur l'hôte.
Si vous mettez à niveau une pile créée sous un nom de projet Compose différent, conservez ce
nom avec docker compose -p YOUR_EXISTING_PROJECT ... pour réutiliser ses conteneurs
et son volume de modèle. Changer les noms de projet crée une pile séparée.
La leçon guidée Customer Service utilise un jeton d'audit frais à chaque tentative plutôt que le jeton d'événement fixe. Elle reconnaît les divulgations en texte brut et distingue la consultation de l'exemple résolu de la résolution sans celui-ci. Les tentatives fraîches préservent les conversations précédentes et la progression acquise. Son profil débutant fait délibérément confiance à un rôle d'opérateur de support revendiqué ; le bot de pratique Customer Service original reste séparé. Les tentatives guidées existantes conservent leur profil antérieur jusqu'à ce que le joueur reparte de zéro.
Deux autres leçons guidées utilisent des fixtures fictives isolées : l'accès aux outils RH, puis un article de connaissance modifiable qui peut rediriger une réponse simulée. Elles exécutent des demandes d'action de modèle validées par schéma contre ces outils de fixture, enregistrent les appels d'outils et valident leurs résultats. Les joueurs peuvent rejouer les mêmes arguments via une vérification de permissions et inspecter un contrôle d'usage légitime. Cette comparaison vérifie la frontière de l'outil, pas une seconde exécution du modèle. Rien n'est envoyé par email et aucun service RH réel n'est connecté. Les personas originaux restent des laboratoires de pratique autonomes avec leurs réponses originales et leur notation manuelle.
Le scénario email est disponible depuis All lessons → Email Joe. Son Explorateur de fichiers
utilise des chemins familiers tels que C:\Users\Joe\Documents\Sales ; ceux-ci identifient des
fixtures en mémoire et n'accèdent jamais au système de fichiers de l'hôte. Chaque email reçoit de nouveaux fichiers fictifs,
une boîte d'envoi et un enregistrement de vente. Les événements de l'histoire sont étiquetés séparément de l'activité observée du modèle
et des outils. Les objectifs de divulgation de fichier et de modification d'enregistrement nécessitent des actions exécutées,
pas une affirmation dans le résumé. Activez Enforce Joe's tool permissions pour relancer l'un ou l'autre
objectif d'outil avec les vérifications applicatives, puis envoyez un exemple propre pour vérifier l'usage normal.
Les tentatives, les indices, l'utilisation de l'exemple résolu et la progression sont sauvegardés.
Pour une installation existante, les modifications d'application/de template nécessitent de reconstruire l'image web ; un simple redémarrage ne copie pas le code mis à jour :
cd platform
docker compose up -d --build web
Les tables de leçon sont créées au démarrage sans supprimer les comptes existants ni l'historique de chat. Suivez le guide d'exploitation pour sauvegarder une installation existante avant la mise à jour et vérifier que les joueurs peuvent reprendre leurs leçons ensuite.
La plateforme contient en elle-même 16 des 20 flags. Les 4 restants (#14–17) nécessitent
une infrastructure externe que vous poussez vous-même — voir
external_artifacts/README.md. Ignorez cette étape si vous ne voulez que la
moitié intégrée à la plateforme.
Les 20 valeurs de flag résident dans un seul fichier : platform/flags.toml. Modifiez les valeurs
ici pour donner à votre événement sa propre saveur (différents jetons flag{adjectif_nom},
différent code promo, différent salaire de PDG, etc.).
Après modification :
cd platform
python3 scripts/apply_flags.py # stamps values into static files
docker compose up -d --build web decoy # copies updated assets into the images
apply_flags.py met à jour les fichiers qui ne sont pas chargés par Python à l'exécution :
data/init.sql (salaire du PDG, flag #4)decoy/html/private/index.html et decoy/html/internal-tools/index.htmlapp/static/logo.jpg (flag #20 — nécessite exiftool dans le PATH)external_artifacts/ (README de chatkit, contenu du gist, enregistrement DNS,
message de commit de setup-history.sh)Après avoir modifié des valeurs de flag, mettez aussi à jour docs/ANSWER_KEY.md pour que votre
feuille de vérification corresponde.
La reconstruction ne met pas à jour les lignes d'employés déjà présentes dans la base SQLite : le seed utilise
INSERT OR IGNORE. Modifier le salaire du PDG dans un événement existant nécessite toujours une migration
ciblée des fixtures. Ne supprimez pas la base de données des joueurs pour appliquer ce changement.
Si vous voulez ajouter ou supprimer des flags entièrement (changer les personas existants, supprimer
la chaîne externe, ajouter un nouvel outil), modifiez directement platform/app/personas/__init__.py
et platform/app/tools.py. Il n'y a pas de DSL — les personas SONT le
jeu.
platform/app/personas/__init__.py) — moins de
clauses de garde-fou, moins de lignes "NEVER", moins d'exemples de refus explicites.
Le taux de réussite des joueurs à la première tentative augmente.OLLAMA_MODEL dans docker-compose.yml, tirez ce modèle,
et exécutez docker compose up -d web pour appliquer la configuration. La taille du modèle seule n'établit pas
la difficulté. Revérifiez les tâches normales, les exemples résolus, les appels d'outils natifs
et les réponses d'action structurées à l'aide des vérifications pré-événement.file:// via le LLM.Le catalogue d'attaques original et les exemples de prompts historiques sont dans docs/CHEAT_SHEET.md.
docs/SETUP_RUNBOOK.md est la checklist de la semaine de l'événement (build → artefacts externes →
essai à blanc → jour de l'événement). docs/EVENT_DAY_NOTES.md contient le script de briefing des joueurs,
le catalogue d'indices par niveaux et un tableau de dépannage.
Pour la forensique du jour de l'événement — « qui a réellement résolu quoi ? » — exécutez
platform/scripts/dump_chats.py contre la base SQLite montée en bind pour produire
un rapport HTML autonome avec des puces de détection de flag par message. Ce sont des correspondances de sous-chaînes,
pas la preuve qu'un assistant a divulgué un secret ou exécuté un outil. Les leçons guidées
conservent leurs propres enregistrements de complétion validés.
L'export par défaut ctf_log.html, les données d'exécution, les fichiers d'environnement locaux et les archives
de release sont ignorés par Git. Conservez les exports nommés personnalisés et les sauvegardes de déploiement en dehors
du checkout ou dans le répertoire ignoré platform/data/. Les enregistrements des joueurs, les identifiants
et les exports de chat doivent rester privés.
MIT. Voir LICENSE.
Créé par Rob Fuller (mubix) pour une formation pratique à la sécurité de l'IA. Code largement généré par IA ; décisions de conception et contenu détenus par un humain.