
Plataforma local de Capture-the-Flag com IA, com lições guiadas sobre injeção de prompt, abuso de chamadas de ferramentas e OSINT contra seis personas de chatbot simuladas.
Um AI Capture-the-Flag local com lições guiadas para profissionais de tecnologia que estão começando em prompt injection. Os jogadores também podem explorar seis personas de IA (uma oculta) que protegem 20 flags por meio de prompt-injection, abuso de tool-call, manipulação de lógica de negócio, fingerprinting de supply-chain, reconhecimento web e OSINT.
O caminho guiado cobre injeção direta, autorização de ferramentas e injeção por meio de um artigo de conhecimento editável. Ele fornece dicas, tentativas salvas, evidências de ferramentas, feedback de conclusão e comparações de ferramentas protegidas. Os laboratórios de prática originais mantêm a pontuação manual de eventos. A inferência do modelo roda localmente via Ollama; após o build e o download do modelo, a plataforma principal não precisa de conexão com a internet.
Email Joe in Product Sales adiciona uma caixa de entrada simulada e uma área de trabalho no estilo Windows. Escreva um e-mail que o assistente do Joe lerá, depois observe o resumo real do modelo e as ações registradas. Três objetivos cobrem um briefing de vendas enganoso, a divulgação de um arquivo interno fictício e um desconto não autorizado. Nenhum servidor de e-mail, Windows, Wine ou modelo adicional é necessário.
ai-ctf/
├── README.md ← você está aqui
├── LICENSE ← MIT
├── platform/ ← tudo o que roda no Docker
│ ├── flags.toml ← config central: edite isto para personalizar os valores das flags
│ ├── docker-compose.yml ← três serviços: web, ollama, decoy
│ ├── Dockerfile ← a imagem do app web
│ ├── app/ ← código-fonte FastAPI (config, personas, tools, chat)
│ ├── data/init.sql ← esquema SQLite + dados de seed de funcionários falsos
│ ├── decoy/ ← nginx minúsculo com duas páginas de flag
│ └── scripts/
│ ├── apply_flags.py ← grava os valores de flags.toml nos arquivos estáticos
│ ├── render_secret.py ← roda na inicialização do contêiner
│ └── dump_chats.py ← exporta o log de chat como HTML (ferramenta do dia do evento)
├── external_artifacts/ ← o que você publica no GitHub / Gist / DNS
│ ├── README.md ← checklist de configuração
│ ├── anvil_chatkit/ ← o pacote falso de supply-chain
│ ├── gist_content.md ← cole isto em um Gist público
│ └── dns_records.txt ← registro TXT a adicionar ao seu domínio
└── docs/ ← a papelada para rodar o evento
├── ANSWER_KEY.md ← soluções guiadas + respostas originais das 20 flags
├── CHEAT_SHEET.md ← soluções funcionais + dicas em níveis (somente GM)
├── OPERATIONS.md ← atualizações, backups e solução de problemas
├── SETUP_RUNBOOK.md ← semana do evento, passo a passo
└── EVENT_DAY_NOTES.md ← script de briefing + solução de problemas
Use o quick start abaixo para o caminho guiado. O guia de operações cobre atualizações, backups, recuperação e verificações pré-evento. O answer key, o cheat sheet, o setup runbook e as notas do evento descrevem o formato opcional do CTF original.
apply_flags.py e
dump_chats.py — o app em si roda dentro do Docker).exiftool (necessário apenas se você alterar a flag de EXIF e quiser que
apply_flags.py regrave o logo).pip install e o pull do modelo Ollama).
Depois disso, a stack local principal roda offline. A cadeia externa opcional de OSINT precisa de acesso à 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
Registre um nome de usuário; a plataforma gera uma senha de 12 caracteres e a mostra uma vez. Guarde-a para depois. Você é autenticado automaticamente e pode selecionar Start learning. Jogadores que retornam podem fazer login para retomar o progresso salvo.
O projeto Compose se chama ai-ctf e tem sua própria rede e volume de modelo.
Apenas a UI web publica uma porta no host: 18080 por padrão. Defina CTF_WEB_PORT
em platform/.env para escolher outra porta. O Ollama e o decoy não têm portas
publicadas no host; o app se conecta ao seu próprio contêiner Ollama. Nenhum passthrough de GPU está
configurado. CPU e memória ainda são compartilhadas com outras cargas de trabalho no host.
Se estiver atualizando uma stack criada sob um nome de projeto Compose diferente, mantenha esse
nome com docker compose -p YOUR_EXISTING_PROJECT ... para reutilizar seus contêineres
e volume de modelo. Alterar os nomes de projeto cria uma stack separada.
A lição guiada de Customer Service usa um token de auditoria novo por tentativa em vez do token fixo do evento. Ela reconhece divulgações em texto simples e distingue ver o exemplo resolvido de resolver sem ele. Tentativas novas preservam conversas anteriores e o progresso conquistado. Seu perfil de iniciante confia deliberadamente em um papel alegado de operador de suporte; o bot original de prática de Customer Service permanece separado. Tentativas guiadas existentes mantêm seu perfil anterior até que o jogador comece do zero.
Mais duas lições guiadas usam fixtures fictícias isoladas: acesso a ferramentas de RH, depois um artigo de conhecimento editável que pode redirecionar uma resposta simulada. Elas executam solicitações de ação de modelo validadas por esquema contra essas ferramentas de fixture, registram as chamadas de ferramentas e validam seus resultados. Os jogadores podem repetir os mesmos argumentos por meio de uma verificação de permissão e inspecionar um controle de uso legítimo. Essa comparação verifica o limite da ferramenta, não uma segunda execução do modelo. Nada é enviado por e-mail e nenhum serviço real de RH está conectado. As personas originais permanecem laboratórios de prática autodirigidos com suas respostas originais e pontuação manual.
O cenário de e-mail está disponível em All lessons → Email Joe. Seu File Explorer
usa caminhos familiares como C:\Users\Joe\Documents\Sales; eles identificam
fixtures em memória e nunca acessam o sistema de arquivos do host. Cada e-mail recebe arquivos fictícios novos,
uma caixa de saída e um registro de vendas. Eventos da história são rotulados separadamente da atividade observada do modelo
e das ferramentas. Os objetivos de divulgação de arquivo e alteração de registro exigem ações executadas,
não uma alegação no resumo. Ative Enforce Joe's tool permissions para reexecutar qualquer
objetivo de ferramenta com verificações da aplicação, depois envie um exemplo limpo para verificar o uso normal.
Tentativas, dicas, uso de exemplo resolvido e progresso são salvos.
Para uma instalação existente, alterações na aplicação/templates exigem reconstruir a imagem web; apenas reiniciar não copia o código atualizado:
cd platform
docker compose up -d --build web
As tabelas de lições são criadas na inicialização sem excluir contas ou histórico de chat existentes. Siga o guia de operações para fazer backup de uma instalação existente antes de atualizar e verificar se os jogadores podem retomar suas lições depois.
A plataforma contém 16 das 20 flags. As 4 restantes (#14–17) exigem
infraestrutura externa que você mesmo publica — veja
external_artifacts/README.md. Pule essa etapa se você só quer a metade
dentro da plataforma.
Todos os 20 valores de flag ficam em um arquivo: platform/flags.toml. Edite os valores
ali para dar ao seu evento um sabor próprio (diferentes tokens flag{adjetivo_substantivo},
código de cupom diferente, salário do CEO diferente, etc.).
Após editar:
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 atualiza os arquivos que não são carregados pelo Python em tempo de execução:
data/init.sql (salário do CEO, flag #4)decoy/html/private/index.html e decoy/html/internal-tools/index.htmlapp/static/logo.jpg (flag #20 — precisa de exiftool no PATH)external_artifacts/ (README do chatkit, conteúdo do gist, registro DNS,
mensagem de commit do setup-history.sh)Depois de alterar quaisquer valores de flag, atualize também docs/ANSWER_KEY.md para que sua
folha de verificação corresponda.
Reconstruir não atualiza linhas de funcionários já existentes no banco SQLite: o seed usa
INSERT OR IGNORE. Alterar o salário do CEO em um evento existente ainda exige uma migração
direcionada de fixture. Não exclua o banco de jogadores para aplicar essa alteração.
Se você quiser adicionar ou remover flags por completo (alterar quais personas existem, remover
a cadeia externa, adicionar uma nova ferramenta), edite platform/app/personas/__init__.py
e platform/app/tools.py diretamente. Não há DSL — as personas SÃO o
jogo.
platform/app/personas/__init__.py) — menos
cláusulas de guardrail, menos linhas "NEVER", menos exemplos explícitos de recusa.
A taxa de sucesso na primeira tentativa dos jogadores aumenta.OLLAMA_MODEL em docker-compose.yml, faça o pull desse modelo
e rode docker compose up -d web para aplicar a configuração. O tamanho do modelo por si só não
estabelece a dificuldade. Reverifique tarefas normais, exemplos resolvidos, chamadas nativas de ferramentas
e respostas de ação estruturadas usando as verificações pré-evento.file:// via o LLM.O catálogo original de ataques e prompts de exemplo históricos estão em docs/CHEAT_SHEET.md.
docs/SETUP_RUNBOOK.md é o checklist da semana do evento (build → artefatos externos →
dry run → dia do evento). docs/EVENT_DAY_NOTES.md tem o script de briefing dos jogadores,
o catálogo de dicas em níveis e uma tabela de solução de problemas.
Para forense do dia do evento — "quem realmente resolveu o quê?" — rode
platform/scripts/dump_chats.py contra o banco SQLite montado via bind para produzir
um relatório HTML autocontido com chips de detecção de flag por mensagem. Essas são correspondências
de substring, não prova de que um assistente divulgou um segredo ou executou uma ferramenta. As lições
guiadas mantêm seus próprios registros de conclusão validados.
A exportação padrão ctf_log.html, dados de tempo de execução, arquivos de ambiente locais e arquivos
de release são ignorados pelo Git. Mantenha exportações com nomes personalizados e backups de implantação fora
do checkout ou no diretório ignorado platform/data/. Registros de jogadores, credenciais
e exportações de chat devem permanecer privados.
MIT. Veja LICENSE.
Criado por Rob Fuller (mubix) para treinamento prático em segurança de IA. Código em grande parte gerado por IA; decisões de design e conteúdo de autoria humana.