
fleet-cve-scanner v1.1.0
Um scanner de CVE de código aberto e script único para frotas gerenciadas por RMM. Puro PowerShell 7 — combina seu inventário de software RMM com NVD, CISA KEV, EPSS e SSVC para responder: esta versão é vulnerável e qual é a urgência?
fleet-cve-scanner
Um scanner de CVE de código aberto, script único para frotas gerenciadas por RMM. PowerShell 7 puro, sem agentes, sem appliances, sem taxas de licença.
Ele responde a uma pergunta para cada software em cada endpoint que você gerencia: a versão instalada é conhecida por ser vulnerável e quão urgente é? — combinando o inventário de software do seu RMM com feeds de segurança gratuitos e autoritativos:
- NIST NVD — CVEs conhecidos + faixas de versões afetadas
- CISA KEV — explorados ativamente na natureza (ignora o limiar de pontuação)
- EPSS — probabilidade de exploração nos próximos 30 dias
- CISA SSVC — decisões de priorização act / attend / track
- MSRC — prova de que um patch da Microsoft já cobre a descoberta
- endoflife.date — software que nunca mais será corrigido
Saídas: um relatório CSV por dispositivo, um histórico SQLite com relógios SLA e eventos de mudança semana a semana, um painel HTML autônomo e um relatório opcional de exposição em markdown.
Status
v1.0.0. O mecanismo foi portado em sala limpa de um scanner que rodava semanalmente em produção contra uma frota Windows (veja docs/HISTORY.md). Antes deste lançamento, os dois foram executados contra a mesma frota ao vivo e comparados linha por linha: em dezenas de milhares de descobertas onde ambos viram um (dispositivo, software, versão) idêntico, todos os campos calculados — status, CVSS, gravidade, flag KEV, decisão SSVC, versão de correção — coincidiram exatamente.
Essa comparação cobre a lógica de veredito. Ela não exerceu a camada de histórico/SLA e não substitui a validação da ferramenta no seu próprio ambiente. Leia docs/known-limitations.md antes de confiar nela — está escrito para ser honesto, não lisonjeiro.
Quick start
Você precisa do PowerShell 7 (pwsh). Duas maneiras de executar:
A. Varredura NinjaOne ao vivo
cp config.example.json config.json
# edit config.json: fill ninjaone.client_id / client_secret / base_url,
# set output.report_dir, and (recommended) nvd.api_key
pwsh -File fleet-cve-scan.ps1
B. Offline — qualquer RMM, SCCM ou Intune (sem acesso à API)
Exporte seu inventário para um CSV com colunas hostname, software, version (opcional device_id, os), depois:
cp config.example.json config.json # only output.report_dir is needed here
pwsh -File fleet-cve-scan.ps1 -InputCsv inventory.csv
-InputCsv faz zero chamadas NinjaOne — sem OAuth, sem API. Ainda consulta NVD e outros feeds públicos, então você ainda precisa de um nvd.api_key no config.json e um output.report_dir válido. Veja docs/rmm-adapters.md para o contrato de entrada e receitas de exportação por RMM.
Instalando pré-requisitos
- PowerShell 7 — macOS:
brew install powershell; Windows:winget install Microsoft.PowerShell; Debian/Ubuntu: instale a partir do repositório de pacotes da Microsoft (packages.microsoft.com). - sqlite3 (opcional, alimenta histórico/trending) — macOS: pré-instalado ou
brew install sqlite; Debian/Ubuntu:apt-get install sqlite3; Windows: baixe o pacote "tools" do SQLite de sqlite.org e coloquesqlite3.exenoPATHou ao lado do script. Sem ele, a varredura ainda é executada;first_seenrecai para a data da execução.
Requisitos
- PowerShell 7 (7.4+ recomendado). A varredura paralela requer 7.0+.
- sqlite3 — opcional; permite o banco de dados de histórico, trending e rastreamento de
first_seendo SLA. Ausente = esses recursos são ignorados, a varredura ainda é concluída. - Egresso de rede para NVD, CISA (KEV),
epss.empiricalsecurity.com(o host de pontuação em massa EPSS — a FIRST moveu a hospedagem de dados EPSS para lá), MSRC, endoflife.date e GitHub raw (CVE ProgramcvelistV5) — mais a API NinjaOne no modo ao vivo. - Credenciais — modo ao vivo precisa de client id/secret OAuth2 do NinjaOne; modo offline precisa apenas de um CSV de inventário. Uma chave de API NVD é tecnicamente opcional, mas efetivamente necessária em escala de frota: NVD permite 50 requisições/30s com chave e apenas 5/30s sem. O scanner detecta qual você tem e limita para corresponder, então uma execução sem chave está correta, mas cerca de 10x mais lenta — bom para um punhado de produtos, impraticável para uma frota real. Chaves são gratuitas.
Referência de configuração
A configuração é um arquivo JSON (padrão config.json ao lado do script; substitua com -ConfigPath). Comece com config.example.json. Toda chave que o scanner lê, seu padrão quando omitida e o que faz:
ninjaone (modo ao vivo)
| Chave | Padrão | Propósito |
|---|---|---|
ninjaone.client_id | "" | ID do cliente OAuth2 da API NinjaOne. Necessário para varreduras ao vivo; deixe em branco para -InputCsv. |
ninjaone.client_secret | "" | Segredo do cliente OAuth2 da API NinjaOne. |
ninjaone.base_url | — (exemplo fornece https://app.ninjarmm.com) | URL base da API NinjaOne; necessária para varreduras ao vivo, sem fallback embutido. Use o host da sua região (ex.: eu.ninjarmm.com, oc.ninjarmm.com). |
nvd
| Chave | Padrão | Propósito |
|---|---|---|
nvd.api_key | "" | Chave da API NVD, enviada como cabeçalho apiKey. Em branco executa não autenticado, o que reduz os padrões de nvd_rate_limit e nvd_min_spacing_ms para o teto anônimo da NVD (4/30s, 6500ms) em vez do autenticado (48/30s, 700ms). Gratuito e ~10x mais rápido. |
Varredura & pontuação
| Chave | Padrão | Propósito |
|---|---|---|
cvss_threshold | 7.0 | Pontuação base mínima de CVSS para que um CVE pontuado seja reportado como VULNERABLE. CVEs listados no KEV ignoram esse piso. |
ssvc_mission_prevalence | high | Entrada de stakeholder Prevalência de Missão do SSVC (low / medium / high). |
ssvc_public_wellbeing | high | Entrada de stakeholder Bem-Estar Público do SSVC (low / medium / high). |
Cache & limite de taxa
| Chave | Padrão | Propósito |
|---|---|---|
nvd_cache_ttl_days | 7 | Dias que um resultado NVD (por nome de software) permanece em cache antes de ser consultado novamente. |
nvd_cache_flush_every | 500 | Checkpoint do cache NVD em disco a cada N itens concluídos, para que uma varredura interrompida mantenha suas buscas. 0 desabilita (salvamento ao final da varredura ainda é executado). |
nvd_min_spacing_ms | 700 com chave API, 6500 sem | Milissegundos mínimos entre chamadas NVD. A restrição limitante de taxa — ajuste esta primeiro. |
nvd_rate_limit | 48 com chave API, 4 sem | Limite máximo de chamadas NVD por janela de 30s (um backstop). Mínimo de 1. |
parallel_throttle | 20 | Contagem de runspaces do ForEach-Object -Parallel. Chamadas NVD são serializadas independentemente; isso apenas limita a concorrência de cache-hit. Mínimo de 1. |
kev_cache_ttl_hours | 24 | TTL para o catálogo CISA KEV em cache. |
epss_cache_ttl_hours | 24 | TTL para o arquivo de pontuação EPSS da FIRST.org em cache. |
eol_cache_ttl_days | 7 | TTL para consultas endoflife.date em cache. |
msrc_cache_ttl_days | 30 | TTL para dados MSRC CVRF em cache. |
cvelist_cache_ttl_days | 7 | TTL para dados SSVC do CVE Program (cvelistV5) / CISA-ADP em cache. |
cvelist_fetch_budget | 300 | Máximo de buscas de registros CVE por execução para enriquecimento SSVC/vulnrichment; o restante adia para a próxima execução. |
nvd_min_spacing_ms, nvd_rate_limit e parallel_throttle são lidos pelo scanner mas não estão presentes em config.example.json — adicione-os apenas se precisar ajustar. Veja docs/rate-limiting.md.
Enriquecimento & SLA
| Chave | Padrão | Propósito |
|---|---|---|
epss_spike_threshold | 0.10 | Aumento mínimo na pontuação EPSS de uma descoberta entre varreduras para emitir um evento de mudança EPSS_SPIKE. |
sla_days_critical | 14 | Janela SLA (dias a partir de first_seen) para descobertas CRITICAL. |
sla_days_high | 30 | Janela SLA para outras gravidades pontuadas. |
denied_software_csv | "" | Caminho para uma verificação opcional de software negado em CSV. Vazio desabilita a verificação. |
output
| Chave | Padrão | Propósito |
|---|---|---|
output.report_dir | (obrigatório) | Diretório para todas as saídas — CSV, banco de dados de histórico, painel e caches. |
output.wiki_security_page | "" | Caminho opcional para uma página de exposição em markdown. Escrito apenas quando definido. |
output.dashboard_share | "" | Caminho/compartilhamento opcional que recebe uma cópia do painel a cada execução. Vazio = apenas local. |
Saídas
Tudo abaixo termina em output.report_dir.
vuln-report-YYYY-MM-DD.csv— o relatório por descoberta. 28 colunas (esquema abaixo).vuln-history.db— histórico SQLite (requersqlite3):runs(agregados por execução),findings(histórico de descobertas abertas por(dispositivo, software, cve)comfirst_seen/last_seen/resolved_date/epss_score) echanges(eventos de mudança semana a semana tipificados).cve-dashboard.html— painel HTML autônomo (biblioteca de gráficos incorporada, sem requisições externas). Opcionalmente copiado paraoutput.dashboard_share.eol-report-YYYY-MM-DD.csv— escrito quando famílias de fim de vida são detectadas.denied-report-YYYY-MM-DD.csv— escrito quandodenied_software_csvestá configurado e encontra correspondências.- Arquivos de cache —
nvd-cache.json,kev-cache.json,epss-cache.json,eol-cache.json,msrc-cache.json,cvelist-cache.json(todos ignorados pelo git). - Página de exposição em markdown — em
output.wiki_security_page, apenas quando definido.
Esquema do CSV (28 colunas)
O conjunto de colunas é fixo e validado na liberação. Em ordem:
| # | Coluna | Significado |
|---|---|---|
| 1 | device_id | ID do dispositivo RMM (ou um ID sintético determinístico no modo -InputCsv). |
| 2 | hostname | Nome do host do dispositivo. |
| 3 | os | String do sistema operacional (pode estar em branco). |
| 4 | software | Nome do produto conforme inventariado. |
| 5 | installed_version | String da versão conforme inventariada. |
| 6 | cve_id | Identificador do CVE. |
| 7 | cvss_score | Pontuação base CVSS (0 se nenhuma). |
| 8 | severity | Rótulo de gravidade CVSS. |
| 9 | cvss_version | Qual padrão CVSS produziu a pontuação (4.0/3.1/3.0/2.0/em branco). |
| 10 | epss_score | Probabilidade EPSS da FIRST.org (em branco se o CVE estiver ausente do catálogo). |
| 11 | epss_percentile | Percentil EPSS (em branco se ausente). |
| 12 | ssvc_exploitation | Opção de exploração SSVC raw da CISA (none/poc/active; em branco sem dados ADP). |
| 13 | ssvc_decision | Decisão SSVC Act/Attend/Track (em branco sem dados ADP). |
| 14 | status | VULNERABLE / PATCHED / UNKNOWN. |
| 15 | published_date | Data de publicação do CVE. |
| 16 | unknown_reason | Por que uma linha é UNKNOWN (SUSPECT_VERSION / NO_VERSION_BOUND / VERSION_PARSE_ERROR; em branco caso contrário). |
| 17 | is_kev | True quando o CVE está no catálogo CISA KEV. |
| 18 | kev_due_date | Data de vencimento de remediação CISA KEV. |
| 19 | kev_ransomware_use | Flag de uso em campanha de ransomware do KEV. |
| 20 | fix_version | Versão computada do limite de correção. |
| 21 | fix_boundary_inclusive | Se o limite de correção é inclusivo. |
| 22 | advisory_url | URL do aviso do fornecedor ou detalhe do NVD. |
| 23 | patch_evidence | Evidência quando um UNKNOWN da Microsoft foi alterado para PATCHED. |
| 24 | triage_status | Disposição de triagem de triage.json (em branco se nenhum). |
| 25 | triage_note | Nota de triagem. |
| 26 | first_seen | Data em que a descoberta foi observada pela primeira vez (do banco de dados de histórico). |
| 27 | sla_due | Data de vencimento do SLA. |
| 28 | sla_breach | Se o SLA foi violado. |
Agendamento
Run-WeeklyScan.ps1 é um wrapper para execuções agendadas: executa o scanner a partir de seu próprio diretório, captura todos os fluxos de saída para um log datado em <script dir>/logs/ (substitua com -LogDir) e propaga o código de saída do scanner para que o agendador veja falhas.
Agendador de Tarefas do Windows:
schtasks /Create /TN "CVE-Scan-Weekly" ^
/TR "pwsh -NoProfile -File C:\path\to\Run-WeeklyScan.ps1" ^
/SC WEEKLY /D SUN /ST 22:00 /RU SYSTEM
cron (Linux/macOS):
0 22 * * 0 pwsh -File /path/to/Run-WeeklyScan.ps1
Hospedagem do painel
cve-dashboard.html é totalmente autônomo — abra diretamente, coloque em qualquer host estático ou compartilhamento de arquivos, ou copie automaticamente a cada execução via output.dashboard_share. Para hospedagem com controle de acesso, o diretório dashboard-auth/ fornece um host ASP.NET mínimo com autenticação Microsoft Entra (Azure AD); veja seu README e RUNBOOK.
Limitações honestas (leia antes de confiar)
- A correspondência CPE é inerentemente difusa. 40–60% do inventário típico não tem entrada NVD e é ignorado (registrado, nunca silenciosamente). A seleção de CPE baseada em nome pode escolher o produto errado; um fluxo de supressão existe porque precisa. Este é o teto da abordagem NVD gratuita — um scanner pago com um catálogo de detecção curado será mais preciso. O valor desta ferramenta é ser gratuita, transparente e auditável.
- UNKNOWN é um veredito de primeira classe. Quando o scanner não consegue provar vulnerável ou corrigido, ele diz isso em vez de adivinhar.
- Verificado apenas contra NinjaOne. O mecanismo de varredura é independente de RMM (a entrada é apenas dispositivo + software + versão); o modo
-InputCsvpermite que qualquer exportação de RMM/SCCM/Intune o alimente, mas apenas o adaptador NinjaOne foi executado em produção.
A lista completa e sem rodeios — taxa de skip de CPE, mascaramento de chave de dedup, totalResults da página 1, lacunas de substituição do MSRC e mais — está em docs/known-limitations.md.
Notas de design
Algumas escolhas estruturais que parecem não convencionais são deliberadas:
- Arquivo único, não um módulo. O caminho quente da varredura é executado dentro de
ForEach-Object -Parallel, e esses runspaces não conseguem ver funções do escopo externo — por isso um punhado de ajudantes é intencionalmente duplicado dentro do bloco paralelo. Um layout de módulo com uma função por arquivo não removeria essa duplicação (o corpo paralelo ainda precisaria da fonte injetada por runspace); apenas adicionaria uma etapa de compilação e quebraria o modelo de implantação de copiar um arquivo. Se o projeto um dia ultrapassar o arquivo único, o empacotamento é a mudança em forma de v2, não um patch. - Registros
[PSCustomObject], não classes. Os registros de descoberta são produzidos dentro de runspaces paralelos e retornados ao runspace principal. Instâncias de classe do PowerShell não sobrevivem confiavelmente a esse limite;[PSCustomObject]sobrevive, e o contrato de colunas CSV é aplicado pela validação de liberação em vez de um sistema de tipos. - Scripts de teste PS7 simples, não Pester. As suítes em
tests/são scripts sem dependências com asserções de código de saída, executáveis em qualquer lugar quepwshexista — incluindo o servidor de varredura — sem nada para instalar. A CI executa todos eles no Windows e Ubuntu.
Documentação
- docs/how-it-works.md — o pipeline de varredura etapa por etapa, lógica de veredito, disciplina de cache e o contrato de falha suave.
- docs/known-limitations.md — todas as formas conhecidas de o scanner estar errado e por quê.
- docs/rate-limiting.md — as lições de limite de taxa NVD como guia do operador e tabela de ajuste.
- docs/rmm-adapters.md — o contrato de entrada, os dois caminhos de inventário embutidos e como adicionar um adaptador nativo.
- docs/HISTORY.md — histórico de versões condensado e anonimizado e as lições de engenharia por trás de cada lançamento.
Contribuindo
PRs são bem-vindos — adaptadores RMM acima de tudo. Veja CONTRIBUTING.md para as regras básicas e o requisito de direção segura (a lógica de status só pode errar em direção a mais visibilidade, nunca silenciosamente em direção a PATCHED).
Fontes de dados & atribuição
Esta ferramenta só é tão útil quanto os feeds gratuitos e autoritativos contra os quais ela se une. Cada um dos seguintes é consultado no momento da varredura; por favor, honre seus termos se você construir sobre isso.
- NIST National Vulnerability Database (NVD) — registros CVE e faixas de versões afetadas, via API NVD. Este produto usa a API NVD, mas não é endossado ou certificado pelo NVD. https://nvd.nist.gov/
- Catálogo de Vulnerabilidades Exploradas Conhecidas (KEV) da CISA — a lista autoritativa de CVEs conhecidos por serem explorados na natureza. https://www.cisa.gov/known-exploited-vulnerabilities-catalog
- CVE Program —
cvelistV5— registros CVE mais os dados SSVC/vulnrichment contribuídos pelo ADP da CISA. CVE® é uma marca registrada da MITRE Corporation. https://github.com/CVEProject/cvelistV5 - SSVC (Stakeholder-Specific Vulnerability Categorization) — a lógica de decisão act/attend/track nesta ferramenta é derivada do CERT/CC SSVC (Carnegie Mellon University Software Engineering Institute) e da árvore de decisão do Coordenador SSVC da CISA, versão 2.0.3. Crédito ao CERT/CC e à CISA é necessário. https://www.cisa.gov/ssvc · https://github.com/CERTCC/SSVC
- FIRST.org EPSS (Exploit Prediction Scoring System) — probabilidade de exploração nos próximos 30 dias. Dados EPSS são fornecidos pela FIRST. Veja Jay Jacobs, Sasha Romanosky, Benjamin Edwards, Michael Roytman, Idris Adjerid (2021), Exploit Prediction Scoring System, Digital Threats: Research and Practice, 2(3). https://www.first.org/epss/
- Microsoft Security Response Center (MSRC) — a API CVRF, usada para confirmar quando uma atualização de segurança da Microsoft já cobre uma descoberta. © Microsoft Corporation. https://api.msrc.microsoft.com/ · https://msrc.microsoft.com/
- endoflife.date — datas de fim de vida e fim de suporte para software que nunca mais será corrigido. Dados cortesia do projeto endoflife.date. https://endoflife.date/
Licença
Apache-2.0 — veja LICENSE.