
RMM으로 관리되는 환경을 위한 오픈소스 단일 스크립트 CVE 스캐너입니다. 순수 PowerShell 7 기반 — RMM 소프트웨어 인벤토리를 NVD, CISA KEV, EPSS, SSVC와 결합하여 이 버전이 취약한지, 그리고 얼마나 긴급한지에 답합니다.
RMM으로 관리되는 플릿을 위한 오픈소스 단일 스크립트 CVE 스캐너입니다. 순수 PowerShell 7, 에이전트 불필요, 어플라이언스 불필요, 라이선스 비용 없음.
관리하는 모든 엔드포인트의 모든 소프트웨어에 대해 한 가지 질문에 답합니다: 설치된 버전이 알려진 취약점을 가지고 있는지, 그리고 그 긴급성은 어느 정도인지? — RMM의 소프트웨어 인벤토리를 무료 공식 보안 피드와 결합하여.
출력물: 장치별 CSV 보고서, SLA 시계 및 주간 변경 이벤트가 있는 SQLite 히스토리, 독립형 HTML 대시보드, 그리고 선택적 마크다운 노출 보고서.
v1.0.0. 엔진은 Windows 플릿을 대상으로 프로덕션에서 주간 실행되던 스캐너에서 클린룸 방식으로 포팅되었습니다. (docs/HISTORY.md 참조). 이 릴리스 이전에 두 스캐너를 동일한 실제 플릿에 대해 실행하고 행별로 비교했습니다. 수만 건의 결과 중 두 스캐너가 동일한 *(장치, 소프트웨어, 버전)*을 확인한 경우, 모든 계산된 필드(상태, CVSS, 심각도, KEV 플래그, SSVC 결정, 수정 버전)가 정확히 일치했습니다.
이 비교는 판결(verdict) 로직을 다룹니다. 히스토리/SLA 계층을 테스트하지 않았으며, 자체 환경에서 도구를 검증하는 것을 대체하지 않습니다. 신뢰하기 전에 docs/known-limitations.md를 읽으십시오 — 이 문서는 아첨보다는 정직하게 작성되었습니다.
PowerShell 7 (pwsh)이 필요합니다. 두 가지 실행 방법:
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
인벤토리를 hostname, software, version 열(선택 사항 device_id, os)을 가진 CSV로 내보낸 후:
cp config.example.json config.json # only output.report_dir is needed here
pwsh -File fleet-cve-scan.ps1 -InputCsv inventory.csv
-InputCsv는 전혀 NinjaOne 호출을 하지 않습니다 — OAuth 없음, API 없음. 여전히 NVD 및 기타 공개 피드를 쿼리하므로 config.json에 nvd.api_key가 필요하고 유효한 output.report_dir이 필요합니다. 입력 계약 및 RMM별 내보내기 방법은 docs/rmm-adapters.md를 참조하십시오.
brew install powershell; Windows: winget install Microsoft.PowerShell; Debian/Ubuntu: Microsoft 패키지 저장소(packages.microsoft.com)에서 설치.brew install sqlite; Debian/Ubuntu: apt-get install sqlite3; Windows: sqlite.org에서 SQLite "tools" 번들을 다운로드하고 sqlite3.exe를 PATH에 또는 스크립트 옆에 배치. 없어도 스캔은 실행됩니다. first_seen은 실행 날짜로 대체됩니다.first_seen 추적을 활성화합니다. 없으면 해당 기능이 건너뛰고 스캔은 계속 완료됩니다.epss.empiricalsecurity.com (EPSS 벌크 점수 호스트 — FIRST가 EPSS 데이터 호스팅을 이전), MSRC, endoflife.date, GitHub raw (CVE Program cvelistV5) — 라이브 모드에서는 NinjaOne API도 필요.구성은 JSON 파일입니다(기본값은 스크립트 옆의 config.json; -ConfigPath로 재정의 가능). config.example.json에서 시작하십시오. 스캐너가 읽는 모든 키, 생략 시 기본값 및 역할:
ninjaone (라이브 모드)| Key | Default | Purpose |
|---|---|---|
ninjaone.client_id | "" | NinjaOne API OAuth2 클라이언트 ID. 라이브 스캔에 필요; -InputCsv의 경우 비워 둠. |
ninjaone.client_secret | "" | NinjaOne API OAuth2 클라이언트 시크릿. |
ninjaone.base_url | — (example ships https://app.ninjarmm.com) | NinjaOne API 기본 URL; 라이브 스캔에 필요, 내장 대체 없음. 지역 호스트 사용(예: eu.ninjarmm.com, oc.ninjarmm.com). |
nvd| Key | Default | Purpose |
|---|---|---|
nvd.api_key | "" | NVD API 키, apiKey 헤더로 전송. 비워두면 인증되지 않은 상태로 실행되어 nvd_rate_limit 및 nvd_min_spacing_ms의 기본값이 인증된 값(48/30s, 700ms) 대신 NVD의 익명 상한(4/30s, 6500ms)으로 낮아집니다. 무료이며 약 10배 빠릅니다. |
| Key | Default | Purpose |
|---|---|---|
cvss_threshold | 7.0 | 점수가 있는 CVE가 VULNERABLE로 보고되기 위한 최소 CVSS 기본 점수. KEV 목록에 있는 CVE는 이 하한을 우회합니다. |
ssvc_mission_prevalence | high | SSVC Mission Prevalence 이해관계자 입력(low / medium / high). |
ssvc_public_wellbeing | high | SSVC Public Well-being 이해관계자 입력(low / medium / high). |
| Key | Default | Purpose |
|---|---|---|
nvd_cache_ttl_days | 7 | NVD 결과(소프트웨어 이름별)가 재조회 전에 캐시에 유지되는 일수. |
nvd_cache_flush_every | 500 | N개 항목 완료 시마다 NVD 캐시를 디스크에 체크포인트하여 중단된 스캔도 가져온 내용을 유지합니다. 0은 비활성화(스캔 종료 저장은 여전히 실행). |
nvd_min_spacing_ms | 700 with an API key, 6500 without | NVD 호출 간 최소 밀리초. 바인딩 속도 제약 — 이것부터 조정하십시오. |
nvd_rate_limit | 48 with an API key, 4 without | 30초당 NVD 호출의 슬라이딩 윈도우 상한(백스톱). 최소 1. |
parallel_throttle | 20 | ForEach-Object -Parallel 런스페이스 수. NVD 호출은 관계없이 직렬화됨; 캐시 히트 동시성만 제한. 최소 1. |
kev_cache_ttl_hours | 24 | 캐시된 CISA KEV 카탈로그의 TTL. |
epss_cache_ttl_hours | 24 | 캐시된 FIRST.org EPSS 점수 파일의 TTL. |
eol_cache_ttl_days | 7 | 캐시된 endoflife.date 조회의 TTL. |
msrc_cache_ttl_days | 30 | 캐시된 MSRC CVRF 데이터의 TTL. |
cvelist_cache_ttl_days | 7 | 캐시된 CVE Program (cvelistV5) / CISA-ADP SSVC 데이터의 TTL. |
cvelist_fetch_budget | 300 | SSVC/vulnrichment 강화를 위한 실행당 최대 CVE 레코드 가져오기; 나머지는 다음 실행으로 연기. |
nvd_min_spacing_ms, nvd_rate_limit, parallel_throttle은 스캐너가 읽지만 config.example.json에는 없습니다 — 조정이 필요한 경우에만 추가하십시오. docs/rate-limiting.md 참조.
| Key | Default | Purpose |
|---|---|---|
epss_spike_threshold | 0.10 | 스캔 간 발견 항목의 EPSS 점수 상승 최소치, EPSS_SPIKE 변경 이벤트를 발생시킴. |
sla_days_critical | 14 | CRITICAL 발견 항목에 대한 SLA 기간(first_seen 기준 일수). |
sla_days_high | 30 | 기타 점수 심각도에 대한 SLA 기간. |
denied_software_csv | "" | 선택적 거부 소프트웨어 CSV 교차 검사 경로. 비어 있으면 검사 비활성화. |
output| Key | Default | Purpose |
|---|---|---|
output.report_dir | (required) | 모든 출력물(CSV, 히스토리 DB, 대시보드, 캐시)을 위한 디렉터리. |
output.wiki_security_page | "" | 선택적 마크다운 노출 페이지 경로. 설정된 경우에만 작성. |
output.dashboard_share | "" | 각 실행 시 대시보드 복사본을 받는 선택적 경로/공유. 비어 있으면 로컬 전용. |
아래 모든 항목은 output.report_dir에 저장됩니다.
vuln-report-YYYY-MM-DD.csv — 발견 항목별 보고서. 28개 열(스키마는 아래 참조).vuln-history.db — SQLite 히스토리(sqlite3 필요): runs(실행별 집계), findings(각 (device, software, cve)별 열린 발견 히스토리, first_seen/last_seen/resolved_date/epss_score 포함), changes(유형화된 주간 이벤트).cve-dashboard.html — 독립형 HTML 대시보드(차트 라이브러리 인라인, 외부 요청 없음). 선택적으로 output.dashboard_share에 복사.eol-report-YYYY-MM-DD.csv — 수명 종료 제품군이 감지되면 작성.denied-report-YYYY-MM-DD.csv — denied_software_csv가 구성되고 일치할 때 작성.nvd-cache.json, kev-cache.json, epss-cache.json, eol-cache.json, msrc-cache.json, cvelist-cache.json(모두 gitignore됨).output.wiki_security_page에, 설정된 경우에만.열 세트는 고정되어 있으며 게이트에서 강제됩니다. 순서: