
CVE-2020-16899 - Microsoft Windows TCP/IP Vulnerability Detection Logic and Rule
13 октября Microsoft объявила о критической уязвимости в стеке IPv6 Windows, которая позволяет злоумышленнику отправлять специально сформированные пакеты, приводящие к немедленному BSOD (синему экрану смерти) на последних версиях Windows 10 и Windows Server 2019. Хотя эта уязвимость, по-видимому, не позволяет злоумышленнику выполнять код, она может быть использована для массовых атак типа «отказ в обслуживании» на уязвимые версии Windows. Логика обнаружения более опасной версии RCE этой уязвимости находится в CVE-2020-16898: "Bad Neighbor".
Этот документ подготовлен McAfee Advanced Threat Research. Он предназначен для предоставления ценной информации сетевым администраторам и сотрудникам службы безопасности, желающим лучше понять эту уязвимость и защититься от эксплуатации. Представленная здесь сигнатура должна быть тщательно рассмотрена и протестирована в промежуточных средах перед использованием в производстве и может потребовать специальной настройки для целевого развертывания.
Предоставленная информация может быть изменена без уведомления и предоставляется «КАК ЕСТЬ», со всеми недостатками, без каких-либо гарантий относительно точности или применимости информации к какой-либо конкретной ситуации или обстоятельствам, и вы используете её на свой страх и риск. Кроме того, мы не можем гарантировать какую-либо производительность или эффективность любых сигнатур.
Уязвимость является результатом чтения за пределами выделенной памяти, которое может произойти, когда стек IPv6 Windows обрабатывает ICMPv6 Router Advertisement (Type = 134) пакеты, содержащие одну или несколько записей опции DNSSL (Option Type = 31). Назначение записи DNSSL — предоставить список поиска суффиксов DNS-имён, который содержится в её последнем поле. Поскольку этот список поиска может содержать несколько DNS-имён с нулевым завершением, расположенных подряд, поле (а значит, и вся запись) может значительно варьироваться по размеру. Для учёта этого запись опции DNSSL содержит собственное поле Length. Однако, поскольку Length считается в приращениях по 8 байт, по крайней мере одно из доменных имён в списке поиска может иметь дополнительное нулевое заполнение для сохранения 8-байтового выравнивания записи. Именно при обработке этих нулей и возникает уязвимость.
Для каждого доменного имени в списке поиска стек IPv6 Windows выделяет 256-байтовый буфер. Поскольку RFC 1035 ограничивает доменные имена 255 байтами, этого обычно достаточно для размещения доменного имени плюс его нулевого терминатора. Однако код, отвечающий за потребление завершающих нулей в конце каждого доменного имени, имеет верхнюю границу, равную оставшимся байтам в опции, которая может превышать 256 байт. В результате код потребления нулей может ошибочно потребить больше байтов, чем было выделено для буфера, что приводит к чтению за пределами выделенной памяти. В случае, когда буфер находится в конце страницы памяти, такое чтение за пределами может привести к BSOD.
Сигнатура Suricata для этой уязвимости находится в cve-2020-16899.rules и содержит следующую логику:
alert icmp any any -> any any (msg:"Potential CVE-2020-16899 Exploit"; lua:cve-2020-16899.lua; sid:202016899; rev:1;)
Соответствующий Lua-скрипт можно найти в cve-2020-16899.lua. Он содержит логику, необходимую для правильного разбора уровня ICMPv6 и выявления потенциальной эксплуатации CVE-2020-16899, как описано ниже:
После того как мы определили начало уровня ICMPv6, мы проверяем первый байт уровня, чтобы убедиться, что это пакет Router Advertisement ICMPv6 — если нет, выходим.
Поскольку примитивы Suricata не были обновлены для разбора опций ICMPv6, мы просто переходим к 17-му байту уровня ICMPv6, так как именно там должны начинаться опции (первые 16 байт — поля фиксированной длины, согласно RFC 4443). Оттуда мы перебираем каждую опцию, пока не закончатся байты в пакете. Для каждой опции мы начинаем с проверки первого байта, который соответствует полю Option Type. Хотя мы игнорируем все опции, не являющиеся DNSSL, для Option Type = 31 (DNSSL) мы проверяем, больше или равно ли Length (второй байт в опции) 35, минимальной длине, необходимой для срабатывания уязвимости: