Данные об уязвимостях
Как читать CVE: что запись CVE сообщает и о чём молчит
Запись CVE называет уязвимость и указывает на вендора, а исправленную версию определяет бюллетень вендора.
Расставляем приоритеты CVE по каталогу CISA KEV и оценкам EPSS от FIRST рядом с CVSS, затем строим таблицу приоритетов из обоих бесплатных фидов.
Сканер выдал 400 находок, а у вас одна неделя. CVSS отсортирует их по серьёзности, но 9.8, которую никто не использует, может подождать, а 7.5, которую атакующие уже эксплуатируют, ждать не должна. Два бесплатных источника показывают, какие уязвимости применяются на практике. Каталог CISA Known Exploited Vulnerabilities (KEV) перечисляет уязвимости с подтверждённой эксплуатацией. Exploit Prediction Scoring System (EPSS) от FIRST оценивает вероятность эксплуатации каждой уязвимости в ближайшие 30 дней.
В статье объяснены оба источника и их место рядом с CVSS, а в лабораторной работе вы запросите оба фида по одним и тем же CVE и соберёте небольшую таблицу приоритетов. Запомнить стоит вот что: порядок патчинга определяют вместе серьёзность, свидетельства эксплуатации и то, насколько открыты ваши собственные системы. Каждый из этих факторов в отдельности даёт неверный порядок.
Если CVSS вам в новинку, сначала прочитайте, что такое CVSS. Разница между уязвимостью, угрозой и эксплойтом объяснена в статье что такое уязвимость.
Common Vulnerability Scoring System оценивает уязвимость по её вектору: как атакующий до неё добирается, сколько усилий нужно, требуются ли привилегии или действие пользователя и что уязвимость может повредить. Базовая оценка — это число от 0 до 10, построенное из этих свойств.
Базовая оценка отвечает на один вопрос: насколько всё будет плохо, если кто-то этим воспользуется? На вопрос, пользуется ли кто-нибудь, она не отвечает. В CVSS есть временные метрики, которые могут учитывать зрелость эксплойта, но большинство панелей показывает прежде всего базовую оценку, а это число после публикации CVE не меняется.
Две CVE из лабораторной работы ниже показывают этот разрыв. У CVE-2021-44228 (Log4Shell) базовая оценка в NVD равна 10.0. У CVE-2023-44487 (HTTP/2 Rapid Reset) она 7.5. Сортировка только по оценке ставит Log4Shell первой, и это правильно. Проблема проявляется, когда в бэклоге сорок уязвимостей с оценкой 9.8 и нет никаких признаков, что хоть одну применяли. Оценка даёт точку отсчёта, порядка работ из неё не получить.
Каталог KEV — это список CISA с уязвимостями, которые эксплуатировались в реальных атаках. CISA заявляет, что ведёт авторитетный источник этого списка, и рекомендует организациям использовать каталог как входные данные для своей приоритизации. Для включения нужны надёжные свидетельства активного применения уязвимости. Записи появляются по мере появления таких свидетельств.
В файле каталога, скачанном для этой статьи (версия каталога 2026.11.06, выпуск 2026-11-06), 1,769 записей. В каждой есть такие поля:
cveID, vendorProject, product и vulnerabilityNamedateAdded, день, когда CISA добавило CVEdueDate, срок, установленный CISArequiredAction, обычно исправление от вендора или мера смягченияknownRansomwareCampaignUse, со значением Known или Unknownnotes и cwesИз 1,769 записей 361 помечена Known по применению в программах-вымогателях. 285 добавлены в 2026 году до даты выпуска.
У каталога два ограничения. Во-первых, он неполон. Эксплуатация часто начинается раньше, чем CISA её подтверждает, а некоторые эксплуатируемые уязвимости так и не получают записи. CVE, которой нет в KEV, не подтверждена, но безопасной это её не делает. Во-вторых, KEV не сообщает, затронута ли ваша копия продукта. Ответ на это даёт ваша собственная инвентаризация.
Большинство знает сроки KEV по BOD 22-01, обязательной оперативной директиве, которую CISA выпустило 3 ноября 2021 года. Она требовала от федеральных ведомств США устранять записи KEV в течение шести месяцев для идентификаторов CVE, присвоенных до 2021 года, и в течение двух недель для всех остальных уязвимостей. В старых записях поле dueDate до сих пор отражает эту модель.
BOD 22-01 больше не действует. На её странице на cisa.gov теперь сказано, что она отозвана и заменена BOD 26-04, которую CISA указывает под датой 10 июня 2026 года. BOD 26-04 задаёт сроки устранения по четырём входным параметрам:
Сами сроки приведены в Table 1 директивы BOD 26-04. Директива считает календарные дни и определяет записи «& forensic triage», которые надо устранить за три дня и затем проверить на признаки компрометации. Точные значения смотрите в таблице на странице директивы. Не копируйте числа из этой статьи или из старых постов в блогах.
В каталоге видны обе эпохи. В скачанном файле разница между dateAdded и dueDate составляет 21 день для 1,025 записей, 14 дней для 286 записей и около шести месяцев (181 или 182 дня) для 249 записей. Почти у всех записей с шестимесячным сроком идентификаторы CVE относятся к 2020 году или раньше, что совпадает с правилом BOD 22-01. Разницу в 21 день и 14 дней CISA задавало отдельно для каждой записи, поэтому единого правила за ней нет. В 152 записях BOD 26-04 упомянута в requiredAction или notes.
EPSS ведёт FIRST, Forum of Incident Response and Security Teams. FIRST описывает её как модель машинного обучения, которая оценивает вероятность эксплуатации опубликованной CVE в реальных атаках в ближайшие 30 дней. FIRST публикует оценку каждый день для каждой CVE. Данные бесплатны, регистрация не нужна.
Каждая CVE получает два числа:
Большинство оценок близки к нулю, потому что большинство уязвимостей никогда не эксплуатируется. Поэтому перцентиль часто читать проще, чем исходную оценку. Оценка 0.909 сама по себе выглядит высокой, а перцентиль 0.998 показывает её положение относительно остального списка в этот день.
По словам FIRST, модель опирается примерно на 2,850 признаков из пяти категорий (среди прочего код эксплойтов, обсуждения, метрики CVSS, возраст и объём ссылок) и обучается на наблюдаемой эксплуатации, данные о которой поставляют партнёры. Оценки меняются с появлением новых сигналов. API может вернуть историю за 30 дней для одной CVE, что помогает объяснить, почему оценка выросла.
У EPSS есть явное ограничение. Она предсказывает активность эксплуатации. О том, насколько серьёзна уязвимость и работает ли в ваших системах затронутый код, она ничего не говорит. Считайте высокую оценку поводом посмотреть на актив и проверьте актив, прежде чем считать его под угрозой.
Каждый источник отвечает на свой вопрос:
| Источник | На какой вопрос отвечает | Форма ответа |
|---|---|---|
| Базовая оценка CVSS | Насколько всё будет плохо, если кто-то этим воспользуется? | Фиксированная серьёзность, от 0 до 10 |
| KEV | Подтвердило ли CISA эксплуатацию? | Да или нет, с датами |
| EPSS | Насколько вероятна эксплуатация в ближайшие 30 дней? | Вероятность и перцентиль, обновляются ежедневно |
| Ваша инвентаризация | Есть ли уязвимость в моих системах и достижима ли она? | Да или нет, по вашим данным |
Порядок патчинга получается из сочетания всех четырёх. Вот отправная точка, и законом она не считается. Первым идёт подтверждённое и достижимое. Далее подтверждённое, но недостижимое, и неподтверждённое с высокой EPSS и достижимое. Остальное выстраивается по CVSS и ценности актива. BOD 26-04 сочетает такие же входные данные, поэтому федеральные правила следуют той же логике.
Понадобится:
www.cisa.gov, api.first.org и services.nvd.nist.gov.Эти шаги только читают публичные каталоги. Ни один из них не сканирует хосты. Если позже будете проверять столбец открытости на работающих сервисах, делайте это только на своих системах или с письменного разрешения на тестирование.
curl -s https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json -o kev.json
ls -l kev.jsonСкачивание проходит без вывода. При эталонном запуске файл занял 1,832,349 байт. Откройте начало файла и проверьте catalogVersion и dateReleased, прежде чем доверять подсчётам.
jq '.vulnerabilities | length' kev.jsonНа эталонной машине это вернуло command not found, потому что jq не было. Эквивалент на Python вернул:
python -c "import json; d=json.load(open('kev.json')); print(len(d['vulnerabilities']))"1769Поле верхнего уровня count должно показать то же число.
jq '.vulnerabilities[] | select(.cveID=="CVE-2021-44228") | {cveID, dateAdded, dueDate, requiredAction}' kev.jsonЭквивалент на Python напечатал следующее, поле requiredAction здесь сокращено:
{
"cveID": "CVE-2021-44228",
"dateAdded": "2021-12-10",
"dueDate": "2021-12-24",
"requiredAction": "For all affected software assets for which updates exist, the only acceptable remediation actions are: 1) Apply updates; OR 2) remove affected assets from agency networks. ..."
}Тот же запрос для CVE-2023-4863 вернёт dateAdded 2023-09-13 и dueDate 2023-10-04. Файл каталога стоит хранить из-за дат: они показывают, когда CISA приняло меры, в дополнение к самому факту.
curl -s 'https://api.first.org/data/v1/epss?cve=CVE-2021-44228,CVE-2023-4863' | jq '.data'Исходный ответ при эталонном запуске:
{"status":"OK","status-code":200,"version":"1.0","access":"public","total":2,"offset":0,"limit":100,"data":[{"cve":"CVE-2023-4863","epss":"0.999790000","percentile":"0.999800000","date":"2026-11-07"},{"cve":"CVE-2021-44228","epss":"0.999990000","percentile":"1.000000000","date":"2026-11-07"}]}В коде важны две детали. Строки приходят в другом порядке, чем в запросе, поэтому сопоставляйте по cve и никогда не полагайтесь на позицию. Значения приходят строками, так что перед сортировкой или сравнением преобразуйте их в числа.
Сохраните это как priority.py. Нужна только стандартная библиотека Python.
import json, sys, time, urllib.request
KEV_FILE = sys.argv[1]
CVES = sys.argv[2:]
def get(url):
with urllib.request.urlopen(url, timeout=60) as r:
return json.load(r)
kev = {v["cveID"]: v for v in json.load(open(KEV_FILE))["vulnerabilities"]}
epss = {row["cve"]: row for row in get(
"https://api.first.org/data/v1/epss?cve=" + ",".join(CVES))["data"]}
print("| CVE | CVSS 3.1 base | In KEV | EPSS | Percentile |")
print("|---|---|---|---|---|")
for cve in CVES:
nvd = get(f"https://services.nvd.nist.gov/rest/json/cves/2.0?cveId={cve}")
metrics = nvd["vulnerabilities"][0]["cve"].get("metrics", {})
cvss = metrics.get("cvssMetricV31", [{}])[0].get("cvssData", {}).get("baseScore", "n/a")
e = epss.get(cve, {})
print(f"| {cve} | {cvss} | {'yes' if cve in kev else 'no'} | "
f"{float(e.get('epss', 0)):.5f} | {float(e.get('percentile', 0)):.5f} |")
time.sleep(7) # the NVD API rate-limits requests without a keyЗапустите скрипт на шести CVE: две из примеров каталога и четыре, выбранные для контраста с ними.
python priority.py kev.json CVE-2021-44228 CVE-2023-4863 CVE-2024-3400 CVE-2023-44487 CVE-2023-38545 CVE-2024-3094Вывод при эталонном запуске:
| CVE | CVSS 3.1 base | In KEV | EPSS | Percentile |
|---|---|---|---|---|
| CVE-2021-44228 | 10.0 | yes | 0.99999 | 1.00000 |
| CVE-2023-4863 | 8.8 | yes | 0.99979 | 0.99980 |
| CVE-2024-3400 | 10.0 | yes | 0.99999 | 1.00000 |
| CVE-2023-44487 | 7.5 | yes | 0.99999 | 0.99998 |
| CVE-2023-38545 | 9.8 | no | 0.78689 | 0.99591 |
| CVE-2024-3094 | 10.0 | no | 0.90900 | 0.99808 |Столбец открытости скрипт не заполняет, потому что вашу инвентаризацию знаете только вы. Вот как он заполнен при эталонном запуске и что проверялось:
find по шаблону log4j-core*.jar в профиле пользователя и репозитории ничего не нашёл. Результат: нет.libwebp* в /mingw64, /usr и профиле пользователя ничего не нашёл. Результат: нет.curl --version показывает 8.12.1. Затронутый диапазон libcurl по NVD начинается с 7.69.0 и заканчивается до 8.4.0, не включая её. Результат: нет для upstream libcurl. См. оговорку ниже.xz --version показывает 5.6.4. NVD указывает как затронутые 5.6.0 и 5.6.1. Результат: нет.В столбце открытости ошибаются чаще всего. Дистрибутивы Linux и вендоры часто бэкпортируют исправления, поэтому один номер версии может ввести в заблуждение. Прежде чем закрыть строку как безопасную, проверьте бюллетень вендора для своей сборки.
Расставьте строки в порядке патчинга по правилу из раздела выше. Если бы CVE-2021-44228, CVE-2023-4863 или CVE-2024-3400 были достижимы в вашей сети, они стали бы первыми патчами недели, что бы ни говорил остальной список.
У CVE-2023-44487 оценка CVSS ниже, чем у CVE-2023-38545, но её эксплуатация подтверждена, а оценка EPSS равна 0.99999. В списке, где обе достижимы, она идёт первой. Оценка 9.8, которую CISA не подтвердило, смещается вниз.
CVE-2024-3094 ломает простое правило. В данных CISA её нет, но её оценка EPSS равна 0.909, а оценка CVSS 10.0. На этой машине версия не затронута, поэтому строка закрывается. На хосте с xz 5.6.1 та же строка поднимается наверх, потому что оценка говорит об очень вероятной активности эксплуатации, а уязвимость критическая.
https://www.first.org/epss/how-it-works, там описаны калибровка и ограничения.https://epss.empiricalsecurity.com/epss_scores-current.csv.gz и соедините его с файлом KEV по cveID. Так за один проход проверяются сотни CVE.Данные в этой статье прочитаны 2026-11-08 из источников, указанных в метаданных статьи. Количество записей KEV и оценки EPSS со временем меняются, поэтому проверяйте дату своего запуска.
Данные об уязвимостях
Запись CVE называет уязвимость и указывает на вендора, а исправленную версию определяет бюллетень вендора.
Данные об уязвимостях
Что значит оценка CVSS вроде 9.8, как устроены векторы v4.0 и v3.1 и как разобрать и пересчитать вектор вручную.