
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?
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:
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.
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.
Você precisa do PowerShell 7 (pwsh). Duas maneiras de executar:
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
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.
brew install powershell; Windows: winget install Microsoft.PowerShell; Debian/Ubuntu: instale a partir do repositório de pacotes da Microsoft (packages.microsoft.com).brew install sqlite; Debian/Ubuntu: apt-get install sqlite3; Windows: baixe o pacote "tools" do SQLite de sqlite.org e coloque sqlite3.exe no PATH ou ao lado do script. Sem ele, a varredura ainda é executada; first_seen recai para a data da execução.first_seen do SLA. Ausente = esses recursos são ignorados, a varredura ainda é concluída.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 Program cvelistV5) — mais a API NinjaOne no modo ao vivo.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)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. |
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.
outputTudo 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 (requer sqlite3): runs (agregados por execução), findings (histórico de descobertas abertas por (dispositivo, software, cve) com first_seen / last_seen / resolved_date / epss_score) e changes (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 para output.dashboard_share.O conjunto de colunas é fixo e validado na liberação. Em ordem:
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
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.
-InputCsv permite 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.
Algumas escolhas estruturais que parecem não convencionais são deliberadas:
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.[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.tests/ são scripts sem dependências com asserções de código de saída, executáveis em qualquer lugar que pwsh exista — incluindo o servidor de varredura — sem nada para instalar. A CI executa todos eles no Windows e Ubuntu.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).
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.
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/cvelistV5Apache-2.0 — veja LICENSE.
| 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). |
| 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). |
| 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. |
| 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. |
| 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. |
eol-report-YYYY-MM-DD.csv — escrito quando famílias de fim de vida são detectadas.denied-report-YYYY-MM-DD.csv — escrito quando denied_software_csv está configurado e encontra correspondências.nvd-cache.json, kev-cache.json, epss-cache.json, eol-cache.json, msrc-cache.json, cvelist-cache.json (todos ignorados pelo git).output.wiki_security_page, apenas quando definido.| # | 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. |