Recon passivo em agentes de IA, RAG e LLM

Image

Como sete técnicas somente-leitura mapearam cinco agentes de IA em 66 segundos, sem enviar uma única mensagem de chat

A maioria dos testes ofensivos ainda faz recon de sistemas de IA como se fossem aplicações web tradicionais: porta 443, uma tela de login, talvez um prefixo /api. Isso não é o suficiente.

Um alvo com IA não é uma aplicação só. É um ecossistema — camadas de orquestração, pipelines de RAG, vector stores, APIs de inferência e, frequentemente, vários agentes compartilhando o mesmo código-base em portas altas e não padronizadas. As pegadas são diferentes. O recon também deveria ser.

Este artigo percorre esse recon: sete técnicas passivas, um alvo de laboratório, uma ferramenta open-source (SpyAI) e um mapa completo de superfície de ataque produzido antes de qualquer prompt ser digitado.

"Dá para aprender mais sobre um sistema de IA pela infraestrutura do que pela janela de chat."

Swagger expõe endpoints de debug. JSON em /health revela nomes de agentes. Schemas OpenAPI listam paths de ingestão de RAG. JavaScript na UI confirma APIs POST-only que retornam 405 num GET simples. Tudo isso é observável sem credenciais, sem fuzzing e sem conversar com o modelo.

Essa é a diferença entre disparar prompt injections genéricos e mirar no agente, endpoint e trust boundary certos.

Passivo ≠ silencioso

O SpyAI não envia credenciais, não faz fuzzing agressivo e não entrega payloads de exploit. Toda sondagem é somente-leitura: checagens de conexão TCP, requisições HEAD e chamadas GET contra uma wordlist curada.

Mas passivo aqui não significa invisível. O SpyAI gera tráfego de rede de verdade. Rode apenas em sistemas que você possui ou tem permissão explícita para testar — scan não autorizado pode violar lei ou política interna.

Ambiente de laboratório e aviso legal

Todos os exemplos deste artigo são baseados em scans realizados no meu ambiente de laboratório pessoal da Offensive Security. Os endereços IP mencionados, como 192.168.217.21, são endereços privados (RFC1918) usados exclusivamente nesse ambiente isolado e não são acessíveis pela internet pública. Este artigo não divulga informações sensíveis ou proprietárias dos labs da Offensive Security.

# Roda o pipeline completo de recon passivo contra um alvo autorizado.
./spy-ai 192.168.217.21

~66 segundos depois, o SpyAI gera um relatório em Markdown e um log completo de execução:

PortaServiço
22ssh
5432postgresql
8001http
8002http
8003http
8011http
8012http

Sete portas. Cinco na faixa "AI-likely". Um backend PostgreSQL. Zero mensagens de chat enviadas.

Esse padrão — várias portas altas mais um banco relacional — já sugere um deployment multi-agente com armazenamento persistente, provavelmente RAG ou estado de sessão. A arquitetura começa a tomar forma antes mesmo da primeira técnica rodar.

As sete técnicas

1. TCP connect paralelo em portas prováveis de IA

Scanners genéricos param em 22, 80, 443. Stacks de IA vivem em outro lugar: APIs de inferência em 8000–8080, Ollama na 11434, Elasticsearch na 9200, Kibana na 5601, MinIO na 9000/9001.

O SpyAI paraleliza sondagens TCP connect em 106 portas usando um scanner Python só com stdlib — sem depender de nmap:

// Retorna True se o handshake TCP para host:port tiver sucesso dentro do timeout.
def try_port(host: str, port: int, timeout: float) -> bool:
    try:
        with socket.create_connection((host, port), timeout=timeout):
            return True
    except (OSError, socket.timeout):
        return False

// Sonda cada porta em paralelo e retorna a lista ordenada das abertas.
def scan(host: str, ports: Sequence[int], timeout: float, workers: int) -> List[int]:
    open_ports: List[int] = []
    with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as pool:
        futures = {pool.submit(try_port, host, p, timeout): p for p in ports}
        for fut in concurrent.futures.as_completed(futures):
            port = futures[fut]
            if fut.result():
                open_ports.append(port)
    return sorted(open_ports)

Portas entre 8000–8080 são rotuladas como "ai-likely". Serviços conhecidos ganham dicas explícitas: 11434 → Ollama, 9200 → Elasticsearch, 5601 → Kibana.

# Scan de 106 portas comuns + prováveis de IA; 7 voltaram abertas.
$ python3 lib/scan_ports.py 192.168.217.21 -p 22,25,53,80,...,11434,27017
scanning 106 port(s) on 192.168.217.21 ...
open: 7
22 5432 8001 8002 8003 8011 8012

Conclusão: cinco portas consecutivas prováveis de IA num único host não é um chatbot isolado. É uma frota.

2. Fingerprinting de banner HTTP (HEAD /)

Uma vez que portas HTTP-prováveis estão abertas, o SpyAI envia HEAD / — só cabeçalhos, sem corpo.

# Requisição HEAD só pelos headers; a resposta identifica o framework.
$ curl -sS -k -I http://192.168.217.21:8001/
HTTP/1.1 405 Method Not Allowed
server: uvicorn
allow: GET
content-type: application/json

405 + server: uvicorn + allow: GET é assinatura clássica de FastAPI/Starlette: a raiz serve uma UI de chat via GET, não HEAD. Framework confirmado antes de qualquer autenticação.

Todas as cinco portas de agente retornaram a mesma assinatura. Mesma stack, múltiplas instâncias.

O SpyAI também captura headers customizados quando presentes — X-AI-Backend, X-RAG-Provider, X-Model, X-Inference-Engine — que podem identificar o provedor de inferência ou o backend de RAG sem tocar na lógica da aplicação.

Conclusão: um 405 é informação, não um beco sem saída.

3. Enumeração de paths curada

O port scan diz onde. A enumeração de paths diz o quê.

O SpyAI sonda 34 paths por porta HTTP aberta, a partir de uma wordlist agrupada por ecossistema:

CategoriaPaths
FastAPI / Swagger/openapi.json, /docs, /redoc, /health
Compatível com OpenAI/v1/models, /v1/chat/completions
Object storage/minio/health/live, /minio/health/ready
K8s / observabilidade/-/health, /-/metrics, /metrics

Resultados na porta 8001:

PathStatusNotas
/200title="IT Helpdesk Assistant"
/docs200Swagger UI do FastAPI
/redoc200ReDoc
/openapi.json2004.906 bytes
/health200identidade do agente (abaixo)
/chat405allow: POST
# GET não autenticado em /health vaza o nome do agente e a porta associada.
$ curl http://192.168.217.21:8001/health
{"status":"healthy","agent":"IT Helpdesk Assistant","port":8001}

Uma requisição sem autenticação: nome do agente, status de saúde, porta associada.

Conclusão: /health costuma ser o inventário de agentes mais rápido do tabuleiro.

4. Mineração de HTML/JS

Endpoints documentados vivem no OpenAPI. Os não documentados se escondem no JavaScript do frontend.

O SpyAI analisa a página / em busca de chamadas fetch(), uso de axios, atributos data-endpoint e chaves de configuração comuns (apiUrl, endpoint, baseUrl).

// JS do frontend que revela o contrato real de /chat: POST + JSON, session_id na resposta.
const r = await fetch('/chat', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify(body)
});
const d = await r.json();
sid = d.session_id;

Três descobertas, zero necessidade de OpenAPI:

  • /chat é POST-only com corpo JSON (message, session_id opcional).
  • As respostas trazem session_id e response.
  • O estado da sessão é gerenciado pelo cliente — relevante para fixation e manipulação de contexto na fase seguinte.

O GET simples em /chat retornou 405. Fácil de passar batido sem mineração de JS.

Conclusão: a UI de chat é fonte de recon, não só superfície de ataque.

5. Parsing de OpenAPI

Quando /openapi.json retorna 200, o SpyAI extrai todo path e método HTTP.

Porta 8001 — 16 paths:

# Todas as rotas e métodos, extraídos direto do /openapi.json exposto.
GET    /                                   Chat Ui
POST   /chat                               Chat
POST   /browse                             Browse
POST   /upload                             Upload
POST   /summarize                          Summarize Docs
POST   /kb/add                             Kb Add
GET    /kb/search                          Kb Search Endpoint
GET    /kb/topics                          Kb Topics
GET    /debug/db-schema                    Debug Schema
GET    /debug/query                        Debug Query
GET    /logs/last-tool-call                Last Tool Call
GET    /logs/latest                        Logs Latest
POST   /session/new                        New Session
POST   /reset                              Reset
POST   /review                             Review
GET    /health                             Health

O mesmo schema de 16 paths apareceu nas cinco portas de agente. Um código-base, cinco personas, uma única superfície de ataque compartilhada.

Conclusão: OpenAPI é a planta baixa. Trate um Swagger exposto como um painel de admin exposto.

6. Detecção de saúde de agentes

O SpyAI sinaliza respostas JSON de /health que contêm um campo agent — um padrão comum em deployments de LLM baseados em uvicorn.

Inventário completo de agentes de um único scan:

PortaAgente
8001IT Helpdesk Assistant
8002Secure IT Assistant
8003Knowledge Base Assistant
8011Secure Engineering Portal
8012Department Resources Assistant

Cinco personas, um host. Os nomes sugerem trust boundaries e escopos de dados diferentes — um agente de helpdesk provavelmente vê um contexto diferente de um "Secure Engineering Portal". Esse mapeamento direciona o prompt injection e o posicionamento de documentos envenenados na fase seguinte.

Conclusão: nomes de agente são indicadores de escopo, não só rótulos.

7. Mineração de certificado TLS

Em portas HTTPS, o SpyAI roda openssl s_client para extrair subject, issuer, validade e SANs.

Este alvo de laboratório não tinha HTTPS na execução — todos os agentes serviram HTTP puro. Quando há TLS, os SANs costumam revelar hostnames internos, domínios de staging e infraestrutura relacionada, invisível só com DNS. O SpyAI roda essa etapa automaticamente nas portas 443, 8443 e outras prováveis de HTTPS.

Conclusão: certificados são OSINT passivo sentado em toda porta HTTPS.

O quadro completo (66 segundos)

Depois das sete técnicas, este é o mapa completo de superfície para a porta 8001:

PathStatusO que sinaliza
/200Chat UI — alvo de mineração de JS
/docs200Swagger interativo — superfície de ataque por si só
/redoc200Documentação da API
/openapi.json200Schema completo — 16 paths
/health200Identidade do agente
/chat405API POST-only — confirmada via JS

Antes de qualquer teste ativo, um pentester já sabe:

  • Stack: FastAPI + uvicorn (Python).
  • Arquitetura: multi-agente, código-base compartilhado, backend PostgreSQL.
  • Superfície de RAG: /kb/add, /kb/search, /upload, /summarize.
  • Exposição de debug: /debug/db-schema, /debug/query.
  • Tooling de agente: /logs/last-tool-call — possível vazamento de trace de MCP/RAG.
  • Custo: 106 conexões TCP e menos de 200 requisições HTTP (1 HEAD + 34 GET por porta HTTP, mais sondas de health/embedded). Sem credenciais. Sem exploits.

Esse é o ROI do recon: um mapa preciso em menos de um minuto.

Mapeamento para frameworks

Recon passivo não explora achados — ele os mapeia. Esse mapa é o que torna a fase seguinte cirúrgica em vez de ruidosa.

MITRE ATLAS

TécnicaO que o SpyAI revela
AML.T0006 — Active ScanningTCP connect em faixas de porta prováveis de IA
AML.T0007 — Discover AI ArtifactsOpenAPI, Swagger, /health de agente
AML.T0024 — Exfiltration via AI Inference API/kb/search, /debug/query, /logs/*

OWASP Top 10 para LLM (2025)

RiscoRecon
LLM02 — Sensitive Information Disclosure/debug/db-schema, /debug/query, /logs/latest sem autenticação
LLM06 — Excessive Agency/logs/last-tool-call; nomes de agente sugerem escopos de privilégio diferentes
LLM08 — Vector and Embedding Weaknesses/kb/add, /kb/search, /upload mapeiam ingestão e recuperação de RAG

Limites de escopo

O SpyAI é a primeira passada — deliberadamente estreito:

  • Sem detecção de versão (-sV). Rode o nmap separadamente para versões exatas.
  • Sem fuzzing. A wordlist é curada, não exaustiva.
  • Sem autenticação ou entrega de exploit.
  • Dependências: python3, curl, openssl (opcional). Só isso.

O que vem depois

Recon passivo responde: o que está deployado, onde, e o que expõe?

Recon ativo responde: como o sistema se comporta sob pressão?

O ponto de transição é esse mapa. Agora você sabe qual agente atacar, qual endpoint de debug sondar, qual path de RAG envenenar — antes do primeiro prompt pousar.

Se você está construindo capacidade de red team para IA, comece por aqui. Mapeie a stack. Depois, prompte.

Este artigo é o Capítulo 1 de uma série sobre recon de IA — mapeamento passivo antes de qualquer interação com o modelo. O Capítulo 2 cobre recon ativo (teste de contradição, corte de conhecimento, forçar citação). O objetivo é um playbook completo, construído a partir de trabalho de laboratório real.

Experimente você mesmo

# Clone, dê permissão de execução aos scripts e aponte o SpyAI para o seu próprio alvo.
git clone https://github.com/jmessiass/spy-ai.git
cd spy-ai
chmod +x spy-ai lib/scan_ports.py
./spy-ai <seu-alvo-autorizado>

Os relatórios ficam em output/<alvo>-<N>.md, com log completo de execução. As wordlists em data/ são extensíveis pela comunidade — abra uma issue ou PR se encontrar paths que valham a pena adicionar.

É isso, pessoal!

Repositório: github.com/jmessiass/spy-ai

Publicado originalmente em inglês no Medium: Spy Before You Prompt. Esta versão foi adaptada e traduzida para o português.

Referências

Copyright 2026. Designed By B2SEC - Cyber Protection