4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CVEからCVSS、EPSS、KEVの掲載有無をサクッと取得するシェルスクリプト

Last updated at Posted at 2025-09-13

想定読者

  • 日々たくさんの脆弱性情報を確認しておられる情シスやセキュリティ担当の方々
  • NVDやKEVのサイトを巡回することに飽き飽きされている方々

スクリプト

#!/usr/bin/env bash
set -euo pipefail

# Usage:
#   ./cve_enrich.sh /path/to/cve.json
#   cat cve.json | ./cve_enrich.sh
#
# Input: CVE JSON 5.1 (CVE Programの公式スキーマ)
# Output: JSON {cve, published, cvss{baseScore, baseSeverity, vectorString}, kev{dateAdded, reference}, epss, epss_percentile}

# 依存: jq, curl

INPUT="${1:-/dev/stdin}"
INPUT_JSON="$(cat "$INPUT")"

# まずJSONから CVSS/KEV と、もしあれば EPSS を抽出(EPSSはADPに載っている場合のみ)
BASE_JSON="$(
  jq -c '
    {
      cve: .cveMetadata.cveId,
      published: (.cveMetadata.datePublished // .cveMetadata.dateReserved // null),

      # CVSS v3.1(containers.cna.metrics[].cvssV3_1 の最初を採用)
      cvss: (
        [
          .containers.cna.metrics[]?
          | select(has("cvssV3_1"))
          | .cvssV3_1
          | {baseScore, baseSeverity, vectorString}
        ] | first
      ),

      # KEV(ADP: other.type == "kev" の最初を採用)
      kev: (
        [
          .containers.adp[]?
          | .metrics[]?
          | select(.other?.type=="kev")
          | .other.content
        ] | first
      ),

      # EPSS(もしADPに格納されている場合を想定:type=="epss")
      epss_block: (
        [
          .containers.adp[]?
          | .metrics[]?
          | select(.other?.type=="epss")
          | .other.content
        ] | first
      )
    }
  ' <<<"$INPUT_JSON"
)"

CVE_ID="$(jq -r '.cve' <<<"$BASE_JSON")"
# 既にEPSSがJSON内にあるか(score/epss と percentileの両方またはいずれか)
EPSS_SCORE="$(jq -r '.epss_block.epss // .epss_block.score // empty' <<<"$BASE_JSON" || true)"
EPSS_PCTL="$(jq -r '.epss_block.percentile // empty' <<<"$BASE_JSON" || true)"

# JSONにEPSSが無ければ FIRST 公式APIから取得
if [[ -z "${EPSS_SCORE}" || -z "${EPSS_PCTL}" ]]; then
  if [[ -n "$CVE_ID" ]]; then
    EPSS_API_JSON="$(curl -s "https://api.first.org/data/v1/epss?cve=${CVE_ID}&page_size=1000" || true)"
    # 期待: {"data":[{"cve":"CVE-XXXX-YYYY","epss":"0.12345","percentile":"0.98765"}], ...}
    EPSS_SCORE_API="$(jq -r --arg c "$CVE_ID" '.data[]? | select(.cve==$c) | .epss // empty' <<<"$EPSS_API_JSON" || true)"
    EPSS_PCTL_API="$(jq -r --arg c "$CVE_ID" '.data[]? | select(.cve==$c) | .percentile // empty' <<<"$EPSS_API_JSON" || true)"

    # 取得できた方を採用(既にJSON内にEPSSがあればそちらを優先)
    EPSS_SCORE="${EPSS_SCORE:-$EPSS_SCORE_API}"
    EPSS_PCTL="${EPSS_PCTL:-$EPSS_PCTL_API}"
  fi
fi

# 最終JSONの整形(数値化できる値は数値化)
jq -n \
  --argjson base "$BASE_JSON" \
  --arg epss_score "${EPSS_SCORE:-}" \
  --arg epss_pctl  "${EPSS_PCTL:-}" '
  {
    cve: $base.cve,
    published: $base.published,
    cvss: ($base.cvss // null),
    kev: (
      if $base.kev then
        {dateAdded: $base.kev.dateAdded, reference: $base.kev.reference}
      else null end
    ),
    epss: (
      if ($epss_score|length) > 0 and ($epss_score|tonumber? != null)
      then ($epss_score|tonumber)
      else null end
    ),
    epss_percentile: (
      if ($epss_pctl|length) > 0 and ($epss_pctl|tonumber? != null)
      then ($epss_pctl|tonumber)
      else null end
    )
  }'

入力:CVE-ID
出力:CVSSのBase Score、KEVの掲載有無(有の場合は掲載された日付)、EPSSのscoreとpercentile

使いかた

curl https://vulnerability.circl.lu/api/cve/{CVE-ID} | ./cve_search.sh

上記のスクリプトを適当な名前で保存して、Vulnerability-Lookup 1のAPIを叩いて実行します。
{CVE-ID}の箇所を任意の値に変更してください。
(APIを叩く処理をスクリプトの内部に埋め込むと403になってしまったのでパイプで渡しています)

curl https://vulnerability.circl.lu/api/cve/CVE-2025-0282 | ./cve_search.sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  4497  100  4497    0     0  20979      0 --:--:-- --:--:-- --:--:-- 21014
{
  "cve": "CVE-2025-0282",
  "published": "2025-01-08T22:15:09.386Z",
  "cvss": {
    "baseScore": 9,
    "baseSeverity": "CRITICAL",
    "vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H"
  },
  "kev": {
    "dateAdded": "2025-01-08",
    "reference": "https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2025-0282"
  },
  "epss": 0.93263,
  "epss_percentile": 0.99801
}

おわりに

CVEの情報を集めるのはCVE_Priorivizer2などの便利なツールがすでに存在しているので、Pythonが動く環境であればそちらを利用されたほうがよいかと思います。
シェルスクリプトした動かない環境でサクッと調査したいときに使ってみてください。

  1. https://www.vulnerability-lookup.org/

  2. https://github.com/TURROKS/CVE_Prioritizer?utm_source=chatgpt.com

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?