Skip to content

Instantly share code, notes, and snippets.

@blacknon
Created September 11, 2025 00:48
Show Gist options
  • Save blacknon/3e01945bde0e811168384d81653aefa3 to your computer and use it in GitHub Desktop.
Save blacknon/3e01945bde0e811168384d81653aefa3 to your computer and use it in GitHub Desktop.
CVE-IDから必要な情報だけ引っ張ってきてTSVにする簡易スクリプト
#!/usr/bin/env python3
# -*- encoding: UTF-8 -*-
#
# Description: CVEIDの情報をAPIから取得して加工するスクリプト。
# エラーチェックもろくにしていないガバガバスクリプト。
# =============================================
import argparse
import sys
import select
import requests
def is_pipe() -> bool:
"""is_pipe
本スクリプトがパイプから値を受け取っているか否かを確認する
"""
if select.select([sys.stdin, ], [], [], 0.0)[0]:
return True
return False
def get_cve_from_nvdapi(cveid: str):
"""NVD APIからCVE情報を取得し、v3/v2のスコアをTSV形式で返す
- v3系とv2系をそれぞれ1行ずつ
- Primary/SecondaryのうちbaseScoreが高い方を採用
"""
uri = f'https://services.nvd.nist.gov/rest/json/cves/2.0/?cveId={cveid}'
response = requests.get(uri, timeout=30)
data = response.json()
if not data.get('vulnerabilities'):
raise ValueError(f"CVE {cveid} not found")
cve_info = data['vulnerabilities'][0]['cve']
cve_id = cve_info['id']
published = cve_info.get('published', "")
url = None
if cve_info.get("references"):
url = cve_info["references"][0].get("url")
if not url:
url = f"https://nvd.nist.gov/vuln/detail/{cve_id}"
rows = []
metrics = cve_info.get("metrics", {})
# ---- CVSS v3.x ----
v3_metrics = metrics.get("cvssMetricV31", [])
if v3_metrics:
# baseScore の降順で最大のものを採用
best_v3 = max(v3_metrics, key=lambda m: m["cvssData"]["baseScore"])
cvssData = best_v3["cvssData"]
rows.append([
cve_id,
best_v3.get("source", ""),
cvssData.get("version", ""),
cvssData.get("baseSeverity", best_v3.get("baseSeverity", "")),
str(cvssData.get("baseScore", "")),
published,
url
])
# ---- CVSS v2.x ----
v2_metrics = metrics.get("cvssMetricV2", [])
if v2_metrics:
best_v2 = max(v2_metrics, key=lambda m: m["cvssData"]["baseScore"])
cvssData = best_v2["cvssData"]
rows.append([
cve_id,
best_v2.get("source", ""),
cvssData.get("version", ""),
best_v2.get("baseSeverity", ""),
str(cvssData.get("baseScore", "")),
published,
url
])
# TSV文字列に変換(ヘッダ付き)
header = ["CVE-ID", "CVSS付与機関", "CVSSのバージョン", "脅威度スコア", "ベーススコア", "情報公開日", "URL"]
lines = ["\t".join(header)]
for row in rows:
lines.append("\t".join(row))
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="CVE情報を標準入力で受け付けてTSVにして出力する")
parser.add_argument("cveid", nargs="?", help="CVEID。複数指定する場合はスペース区切り。指定しなければ標準入力を使う")
parser.add_argument("--format", "-f", help="フォーマット")
args = parser.parse_args()
# 入力の取得
if args.cveid is not None:
cveid = args.cveid
else:
# pipeか否かで処理を切り替え
if is_pipe():
stdin = input()
cveid = stdin
else:
print("情報を取得するCVEIDを引数で渡すか、標準入力で渡してください.", file=sys.stderr)
sys.exit(1)
data = get_cve_from_nvdapi(cveid)
print(data)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment