Construindo Nossa Base de Dados de Ameaças Cibernéticas para Agentes LLM e SOC
Inicialmente, a tarefa parecia direta: consolidar PDFs, CVEs e artigos de cibersegurança em uma única base de dados e, em seguida, fornecer fragmentos relevantes a um agente LLM através de uma API HTTP. No papel, o fluxo era simples: ingestão, extração de texto, segmentação, construção de vetores e busca. Um protótipo funcional surgiu rapidamente, mas o trabalho real começou depois.
A primeira carga completa de dados revelou que a inteligência de ameaças (TI) não se encaixa bem no modelo de "busca simples em documentos de segurança". Não basta encontrar um parágrafo semelhante; é crucial saber a origem da informação, a data de publicação, a confiabilidade da fonte, os Indicadores de Comprometimento (IOCs) mencionados e se eles ainda são relevantes. Além disso, o sistema precisa lidar com a complexidade de feeds RSS malformados, PDFs volumosos, falhas de processo e reinícios sem gerar duplicatas. Este artigo narra a jornada de um protótipo local de busca documental até um serviço com busca combinada, fontes gerenciadas, suporte a STIX/TAXII e recuperação confiável de backups.
Por que a Busca Vetorial Tradicional é Insuficiente para TI
A principal característica de uma base de dados de TI é que o valor de um documento é intrinsecamente ligado ao tempo e à sua origem. Um artigo sobre um ataque recente é geralmente mais útil do que uma recontagem de dois anos atrás. No entanto, a descrição de um CVE antigo não perde seu valor apenas pela idade. Da mesma forma, um boletim de um fabricante, uma entrada em um agregador RSS e uma mensagem aleatória em um canal não podem ser considerados equivalentes, mesmo que compartilhem palavras. A menção precisa de um CVE-2026-1234 ou de um domínio específico muitas vezes é mais importante do que a similaridade geral dos textos. Imagine dois parágrafos: o primeiro detalha vulnerabilidades de VPN, enquanto o segundo contém apenas uma linha com o número do CVE e o endereço de um servidor malicioso. Uma busca semântica comum pode priorizar o primeiro, mas um analista quase certamente necessitará do segundo.
Diante disso, estabelecemos quatro requisitos essenciais: 1) Dividir o texto por limites de seção, não mecanicamente a cada N tokens. 2) Extrair CVEs, IPs, domínios, URLs, hashes, técnicas MITRE ATT&CK e famílias de malware. 3) Considerar a atualidade de forma diferenciada para notícias, campanhas e materiais de referência. 4) Retornar materiais de confirmação: texto, fonte, URL, data e uma explicação clara da avaliação. Essas decisões moldaram a arquitetura.
Primeira Pilha Tecnológica: Postgres, pgvector e MinIO
Para uma versão mínima viável, optamos por uma arquitetura onde o FastAPI recebe uploads e requisições, delegando o processamento para um manipulador em segundo plano que consome tarefas do Postgres. O Postgres armazena documentos, fragmentos, entidades, relacionamentos, tarefas e representações numéricas de texto via pgvector. O MinIO serve como repositório para arquivos originais e texto extraído. A escolha do modelo BAAI/bge-m3 permite transformar fragmentos de texto em vetores numéricos que capturam seu significado, e o pgvector facilita a comparação desses vetores para encontrar textos semanticamente similares, mesmo com vocabulário distinto. Todas as computações de vetorização ocorrem localmente, com um método simplificado e repetível para testes.
Conscientes da complexidade, evitamos inicialmente Redis, Celery, LangChain e um banco de dados gráfico separado. Uma fila de quatro estados (queued, running, complete, failed) foi implementada no Postgres, e os relacionamentos entre entidades, no volume atual, são gerenciados eficientemente em tabelas relacionais. A ingestão foi simplificada para caminhos explícitos para PDF, RSS e CVE, facilitando a verificação do comportamento de cada fonte. A computação de vetores foi mantida localmente para garantir que os textos de TI e os dados do cliente não saíssem do ambiente controlado. Um painel administrativo e uma interface de linha de comando foram desenvolvidos, pois a interface web não era crítica para o piloto fechado. Essa abordagem minimalista provou ser valiosa quando os problemas começaram a surgir.
Ingestão de PDF, RSS e CVE: Um Fluxo Detalhado
Cada tipo de fonte passa por uma etapa de entrada específica, mas o caminho se unifica após a limpeza. PDFs são salvos no MinIO, com extração de texto via PyMuPDF. Se uma página estiver quase vazia, o reconhecimento óptico de caracteres (OCR) com Tesseract é ativado. RSS é processado em duas fases: primeiro, título, data e link; depois, o texto completo do artigo. CVEs podem ser fornecidos como registros JSON prontos ou via URL da fonte. O sistema então normaliza Unicode e caracteres de espaço em branco, salva o texto extraído como um objeto separado no MinIO, divide o documento em fragmentos baseados em limites de seção, extrai entidades de segurança relevantes usando expressões regulares e dicionários, calcula vetores em pequenos lotes e cria relacionamentos entre fragmentos e entidades. O resultado é gravado como uma única transação atômica no banco de dados, garantindo que ou todo o documento processado seja adicionado, ou nada seja alterado. Para evitar duplicatas, utilizamos external_id, canonical_url e content_sha256. A verificação de duplicatas RSS ocorre antes do download completo do artigo, economizando recursos de rede e processamento. Arquivos originais e dados limpos são mantidos separados intencionalmente, permitindo reprocessamento sem necessidade de re-download caso as regras de extração ou segmentação mudem.
O Impacto do Primeiro Grande Coleta de RSS
Inicialmente, a API criava tarefas e as processava em segundo plano. Essa abordagem funcionou para poucos documentos. No entanto, ao iniciar a coleta de 48 feeds RSS/Atom com um limite de 100 entradas por fonte, a API falhou. Com 374 documentos RSS processados, o contêiner da API foi encerrado com código 137 (OOMKilled=true), indicando falta de memória. A tarefa no Postgres permaneceu como running, impedindo o manipulador em segundo plano de assumi-la. A causa não foi um único objeto grande, mas o processamento simultâneo de downloads de rede, análise de artigos, criação de fragmentos e cálculo de vetores pela API. Uma única resposta do FeedBurner gerou cerca de 1,3 GB de tráfego de rede. O progresso era atualizado raramente, dando a impressão de um processo travado.
Após essa experiência, implementamos várias melhorias: a API agora apenas cria tarefas na fila; o trabalho pesado é executado por um manipulador dedicado; vetores são calculados em lotes de oito fragmentos; a resposta HTTP para RSS ou artigos foi limitada a 2 MB; o texto de um único artigo foi limitado a 60 mil caracteres; a tarefa registra o feed atual, número da entrada, contadores de documentos novos e ignorados; o manipulador marca tarefas não atualizadas há muito tempo como falhas; e a reinicialização verifica duplicatas antes de baixar o artigo. A mesma coleta, após as correções, resultou em 1319 documentos RSS e três PDFs, gerando 4726 fragmentos. Quatro feeds problemáticos foram ignorados por motivos claros: dois retornaram HTTP 403 e outros dois excederam o limite de resposta.
Normalização de Texto e a Necessidade de Reindexação
Após a coleta bem-sucedida, a busca funcionava, mas alguns textos RSS apresentavam caracteres corrompidos como â em vez de travessões e  em vez de espaços inquebráveis. Esse fenômeno, conhecido como mojibake, ocorre quando os bytes são codificados em um formato e lidos em outro. Embora o impacto na qualidade da busca fosse mínimo, o texto de confirmação para o agente parecia pouco profissional. Implementamos um limpador de texto cauteloso que tenta restaurar apenas fragmentos que se assemelham a texto UTF-8, mas que foram lidos incorretamente como latin-1 ou cp1252. Textos em russo e inglês normais não são alterados. Novos documentos foram limpos, mas os 4726 fragmentos antigos permaneceram inalterados. Para eles, um script de reindexação foi criado. Para cada documento, ele recalcula fragmentos, entidades e vetores, substituindo os dados antigos em uma única transação. Se o modelo falhar, o índice anterior permanece funcional. O processamento completo se mostrou muito pesado, então adicionamos um modo --only-bad que seleciona documentos com sinais conhecidos de codificação corrompida. Em uma passagem final e pontual, quatro documentos e 59 fragmentos foram corrigidos, seguidos por algumas combinações raras de cp1252 e caracteres de controle. Descobrimos uma armadilha: a condição "não há o caractere â no banco de dados" é imprecisa, pois ele pode aparecer em nomes próprios e palavras em português. A verificação deve focar em sequências corrompidas conhecidas, não em letras isoladas. A verificação final resultou em 4730 vetores para 4730 fragmentos, zero sequências de codificação corrompida conhecidas e zero espaços inquebráveis. Embora pareça um detalhe, um agente citando uma fonte com caracteres corrompidos diminui a confiança na resposta antes mesmo da análise de conteúdo.
Busca Combinada: Contexto Verificável, Não Apenas Respostas
A busca considera múltiplos fatores: proximidade semântica, correspondência de palavras, confiabilidade da fonte, atualidade temporal e correspondência de entidades como CVEs, domínios, etc. Cada fator possui um peso. A API retorna as partes da pontuação separadamente, permitindo que o usuário ou agente compreenda por que um fragmento apareceu no topo. Não é uma prova matemática de verdade, mas uma folha de pontuação transparente. Para notícias e descrições de ataques ativos, a atualidade tem maior peso. Para CVEs e documentos de referência, a idade é penalizada mais suavemente. A correspondência de uma entidade exata, como um CVE ou domínio, eleva um fragmento mesmo com proximidade semântica imperfeita. O método /v1/agent/context aceita uma pergunta e retorna um conjunto de confirmações: texto do fragmento, título do documento, URL, data de publicação, entidades encontradas e pontuações. O modelo de linguagem não deve tratar o conteúdo como um comando, mas como dados externos que não devem ser cegamente confiáveis. A forma de gerar a resposta pode ser alterada, mantendo as fontes e confirmações.
De Base de Documentos a Serviço de IOC para SOC
O próximo estágio começou com a pergunta: como conectar o primeiro centro de monitoramento de segurança (SOC) ou sistema de gerenciamento de eventos de segurança (SIEM)? A busca semântica por si só é insuficiente. O consumidor necessita de um fluxo de dados estável, filtros, recebimento apenas de novas entradas e um esquema de acesso claro. Adicionamos uma API /v1 versionada e exportação de IOCs em JSON, CSV, STIX 2.1 e um TAXII simplificado somente para leitura. STIX define um formato comum para descrever ameaças, e TAXII especifica como trocá-las pela rede. Cada indicador na saída inclui tipo, valor normalizado, nível de confiança, criticidade, veredicto, marcação de disseminação TLP, tempo de primeira e última observação, número de fontes e links para confirmações. Uma camada de controle de qualidade foi implementada para filtrar IPs privados e de teste, domínios de exemplo reservados, hashes vazios e outros falsos positivos óbvios. Analistas podem confirmar ou rejeitar IOCs, e administradores podem criar regras pontuais de permissão ou bloqueio. Para o piloto, foram implementadas chaves de API, com apenas o hash SHA-256 armazenado no banco de dados. Cada chave tem um limite diário e rastreamento de requisições. O corpus geral é acessível a todas as organizações, enquanto PDFs privados, fontes, tarefas e decisões de analistas são segregados.
A Necessidade de Separar Documentos e Observações de IOCs
Feeds RSS, PDFs e relatórios são adequados para busca documental. Uma lista de IPs ou URLs atualizada rapidamente opera de forma diferente, onde valores exatos, tempo de primeira e última observação, tempo de vida, veredicto e origem de cada entrada são cruciais. Conectamos fontes como DShield, Feodo Tracker, CISA KEV, com enriquecimento via Shodan, ThreatFox, URLhaus e nosso próprio sensor ThreatRadar. As regras variam para cada fonte: IPs do DShield recebem o veredicto unknown (desconhecido), pois a observação de um escaneamento não prova malícia; servidores de comando e controle do Feodo e IOCs do ThreatFox recebem malicious (malicioso); URLs exatos do URLhaus são considerados maliciosos, enquanto domínios ou IPs associados são apenas suspeitos, pois sites legítimos podem ser comprometidos; Shodan adiciona informações sobre um IP já conhecido, mas não aumenta o nível de confiança nem altera o veredicto; nosso sensor importa IPs, tempo, contadores e tipos de atividade. A próxima mudança arquitetural já é visível: o caminho dos documentos analíticos e o caminho das observações exatas precisam ser definitivamente separados. Um documento responde "o que se sabe sobre isso", enquanto uma observação responde "quem, quando e onde viu este IOC". Isso é fundamental porque dez sites podem republicar a mesma notícia, criando a ilusão de dez confirmações independentes. Para um documento, são dez páginas; para TI, é uma observação e nove recontagens.
Infraestrutura Essencial para um Servidor de TI
O piloto fechado opera em um único servidor virtual sob Ubuntu. O Caddy gerencia conexões TLS seguras, com apenas HTTP/HTTPS expostos externamente, enquanto Postgres e MinIO residem na rede interna do Docker. A configuração de produção recusa inicialização com credenciais padrão, token administrativo curto ou verificação de chave de API desativada. O manipulador em segundo plano envia periodicamente um sinal de "estou vivo". A API e o processamento de documentos geram logs estruturados em JSON. Uma utilidade administrativa verifica a disponibilidade dos serviços, chaves ativas, erros de fonte, tarefas pendentes, exportação de teste de IOCs e a existência de backups. Um backup contém um dump SQL, um arquivo MinIO e uma descrição com somas de verificação. O arquivo geral é criptografado com AES-256-CBC e PBKDF2. Imediatamente após a criação, o sistema tenta descriptografá-lo e compara a soma de verificação com a original. Separadamente, é armazenado o SHA-256 do arquivo já criptografado. A soma de verificação garante que o arquivo não foi corrompido, mas não prova que a restauração do sistema será bem-sucedida. Por isso, testamos não apenas a existência do arquivo, mas a restauração completa. Uma cópia criptografada foi baixada para o computador do operador, implantada em volumes Docker separados e conectada a uma API temporária. Um snapshot de 2 de julho continha 1745 documentos, 134041 fragmentos, 98523 entidades, 474 fontes e 1823 objetos MinIO. A verificação de disponibilidade, descrição da API, exportação de IOCs, busca e entrega de contexto funcionaram. Sem essa verificação, o backup permaneceria uma hipótese.
Decisões que se Pagaram e as que Ainda Precisam de Teste
As fronteiras de responsabilidade simples funcionaram bem: a API recebe e entrega dados; o manipulador em segundo plano executa o trabalho pesado; MinIO armazena arquivos; e Postgres permanece o repositório principal para descrições, filas e vetores. Outra escolha acertada foi armazenar confirmações e partes da pontuação desde o início. Adicionar uma geração de resposta elegante sobre essa base é fácil; reconstruir a origem da resposta retroativamente é muito mais doloroso. No entanto, a versão atual não está completa: a fila no Postgres é adequada para um manipulador, mas não para escalabilidade infinita de servidores; TAXII é implementado apenas para leitura e uma coleção; OCR depende da disponibilidade do Tesseract; regras de qualidade são principalmente globais; falta interface web, faturamento automático, alta disponibilidade e failover automático; observações estruturadas, tempo de expiração, revogação e histórico de origem de fontes exigem um modelo separado. Outra conclusão é que o número de IOCs não é o principal indicador. É mais útil medir o atraso da fonte para a plataforma, a taxa de duplicatas, a taxa de falsos positivos, a atualidade, a presença de confirmação primária e o número de descobertas que levaram à instalação de um patch, bloqueio ou rastreamento de ataque. Uma grande base de dados parece impressionante; uma base útil reduz o tempo de resolução. Entendemos que esta arquitetura provavelmente tem pontos controversos e agradecemos críticas, conselhos práticos e experiências de especialistas que já construíram ou implementaram plataformas de TI em SOCs. Estamos particularmente interessados em saber onde nossas soluções podem ser simplificadas, fortalecidas ou revisadas. É possível testar a solução solicitando uma chave de API gratuita em nosso site. Se você construiu um pipeline semelhante, gostaríamos de comparar experiências: onde a fronteira entre documento, observação e IOC pronto é traçada em seu sistema?
Perguntas Frequentes
-
Por que vocês não usaram uma plataforma TIP pronta? Uma TIP (Threat Intelligence Platform) é uma plataforma pronta para coleta e gerenciamento de dados de ameaças. Precisávamos de um serviço de servidor compacto para agentes LLM e um piloto fechado com SOC. Uma implementação própria permitiu validar o modelo de dados e a busca sem a complexidade de uma plataforma maior.
-
Por que usar pgvector e busca full-text simultaneamente? A busca vetorial é boa para encontrar textos semanticamente próximos. No entanto, CVEs exatos, domínios e nomes de ferramentas são frequentemente melhor encontrados por palavras e entidades extraídas. Uma avaliação combinada é mais confiável do que qualquer método isolado.
-
Por que os arquivos originais são armazenados separadamente do Postgres? Isso facilita a migração e a reindexação da base. O Postgres armazena a estrutura e os relacionamentos, enquanto o MinIO armazena o material original e o texto extraído. A reindexação não requer o re-download do documento.
-
Um projeto de TI precisa de um banco de dados gráfico separado? Não necessariamente no início. Enquanto os relacionamentos couberem em tabelas normais e as consultas gráficas não se tornarem um gargalo, um banco de dados separado adicionará mais complexidade operacional do que benefícios.
-
É possível coletar dados do Telegram, fóruns ocultos e "0-days privados" imediatamente? Tecnicamente, é possível conectar algumas fontes, mas os riscos legais, de licenciamento e operacionais são maiores. Primeiro, construímos o rastreamento de origem, controle de qualidade e entrega segura. O acesso a plataformas ocultas fechadas é mais razoável comprá-lo de um fornecedor especializado.








