
Автоматизированный инструмент проверки уязвимостей для 6 CVE dnsmasq (CVE-2026-2291, 4890, 4891, 4892, 4893, 5172)
Автоматизированный инструмент «чёрного ящика» для проверки 6 уязвимостей dnsmasq (май 2026 г.). Отправляет атакующие пакеты на работающее устройство (DUT) и сообщает PASS/FAIL — доступ к исходному коду не требуется.
# Установите DNS DUT на WAN-IP вашего ноутбука через GUI, затем:
sudo python3 dnsmasq_cve_verify.py --laptop <ВАШ_WAN_IP> --dut <LAN_IP_DUT> --dut-pass <SSH_ПАРОЛЬ>
# Пример:
sudo python3 dnsmasq_cve_verify.py --laptop 10.0.0.211 --dut 192.168.1.1 --dut-pass '12345Asdf@'
| CVE | CVSS | Тип | Вектор атаки | Затрагиваемая функция |
|---|---|---|---|---|
| CVE-2026-2291 | 9.2 | Переполнение буфера кучи | Удалённый | extract_name() — всегда активна |
| CVE-2026-5172 | 7.5 | Чтение за границами (OOB) / сбой | Удалённый | extract_addresses() — всегда активна |
| CVE-2026-4890 | 7.5 | DoS через бесконечный цикл | Удалённый | Разбор битовой карты NSEC (--dnssec) |
| CVE-2026-4891 | 5.3 | Чтение за границами кучи (OOB) | Удалённый | Проверка RRSIG (--dnssec) |
| CVE-2026-4892 | 8.4 | Переполнение кучи → root | Локальный/Соседний | CLID DHCPv6 (--dhcp-script + DHCPv6) |
| CVE-2026-4893 | 5.3 | Обход проверки | Удалённый | Проверка источника ECS (--add-subnet) |
Корневая причина: union bigname объявляет char name[MAXDNAME], но управляющие символы могут расширить имя до 2*MAXDNAME+1 байт, вызывая переполнение кучи.
Метод тестирования: Отправляет DNS-запросы с доменными именами, содержащими символы с высоким битом (0x80+), которые внутренне преобразуются в \DDD (4 байта на байт ввода). Если dnsmasq аварийно завершается или перестаёт отвечать, он уязвим.
Исправленное поведение: Отвергает имена с превышением размера корректно (FORMERR/REFUSED) или использует увеличенный буфер.
Корневая причина: Поддельное поле rdlen позволяет extract_name() продвинуть указатель за конец записи. Отрицательное значение оставшихся байтов даёт огромное значение → массовое чтение OOB → сбой.
Метод тестирования: Отправляет DNS-ответы с записями CNAME, где rdlen меньше, чем фактическая закодированное имя. Если dnsmasq аварийно завершается — уязвим.
Исправленное поведение: Проверяет, что указатель остаётся в пределах объявленной границы rdlen после extract_name().
Корневая причина: Разбор битовой карты NSEC продвигает указатель на p[1] вместо p[1]+2 (пропущен размер заголовка окна). При bitmap_length=0 указатель никогда не двигается → бесконечный цикл.
Метод тестирования: Отправляет сфабрикованную запись NSEC с window=0, bitmap_length=0. Если dnsmasq перестаёт отвечать на ВСЕ запросы (зависает, не вылетает), он уязвим. Эксплуатируется ДО проверки RRSIG.
Исправленное поведение: Продвигает указатель на p[1]+2 и пропускает битовые карты нулевой длины.
Корневая причина: rdlen в RRSIG не проверяется на минимальный размер (18 + имя подписывающего). Вычисленная длина подписи становится отрицательной → трактуется как огромная → чтение OOB.
Метод тестирования: Отправляет записи RRSIG с rdlen=10 (значительно ниже минимума в 31+ байт). Сбой = уязвим.
Исправленное поведение: Проверяет rdlen >= fixed_fields + signer_name_length перед вычислением длины подписи.
Корневая причина: CLID DHCPv6 (до 65535 байт) кодируется в hex через sprintf("%.2x") в daemon->packet (5131 байт). CLID размером 3000 байт → hex-строка 6000 байт → переполнение. Вспомогательный процесс работает от root.
Метод тестирования: Отправляет DHCPv6 SOLICIT с Client Identifier размером 3000 байт. Требуется IPv6-соседство и настроенный --dhcp-script. Сбой вспомогательного процесса = уязвим.
Исправленное поведение: Усекает или проверяет длину CLID перед hex-кодированием.
Примечание: Некоторые сборки скомпилированы с -DNO_DHCP6 и НЕ подвержены этой CVE.
Корневая причина: process_reply() передаёт длину OPT-записи (~23 байта) вместо полной длины пакета в check_source(). Все проверки границ не срабатывают → функция всегда возвращает 1 (допустимо).
Метод тестирования: Отправляет DNS-запросы с опцией EDNS Client Subnet, содержащей поддельные префиксы источника. Если dnsmasq эхом возвращает ECS без проверки, он уязвим.
Исправленное поведение: Передаёт полную длину пакета в check_source(), что позволяет проводить корректные проверки границ согласно RFC 7871, раздел 9.2.
Обновление до dnsmasq 2.92rel2 (рекомендуется)
dnsmasq_cve_verify.py)Основной инструмент контроля качества. Запускается на тестовом ноутбуке, отправляет атакующие пакеты на DUT и выдаёт чёткий результат PASS/FAIL для каждой CVE. Не требует модификации DUT, кроме SSH-доступа только для чтения для проверки состояния.
┌─────────────────────────────────────────────────────────────────────┐
│ Testing Laptop │
│ │
│ LAN interface WAN interface │
│ <LAPTOP_LAN_IP> <LAPTOP_WAN_IP> │
│ │ │ │
│ │ ┌────┴──────────────┐ │
│ │ │ Malicious DNS │ │
│ │ │ Server (port 53) │ │
│ │ └────┬──────────────┘ │
│ │ │ │
└────────┼───────────────────────────────┼────────────────────────────┘
│ LAN subnet │ WAN subnet
│ │
┌────────┼───────────────────────────────┼────────────────────────────┐
│ │ │ │
│ LAN: <DUT_LAN_IP> WAN: <DUT_WAN_IP> │
│ (LAN gateway) (WAN uplink) │
│ │
│ DUT (Linksys Router) │
│ dnsmasq (any version < 2.92rel2) │
│ │
│ resolv-file=/etc/resolv.conf │
│ → nameserver <LAPTOP_WAN_IP> ← set via GUI, forwards to us │
│ │
└─────────────────────────────────────────────────────────────────────┘
Data flow:
1. Tool sends DNS query to DUT LAN IP (port 53)
2. DUT's dnsmasq can't resolve locally → forwards upstream to LAPTOP_WAN_IP
3. Our malicious server on WAN interface replies with exploit payload
4. DUT's dnsmasq processes the malicious response → crash/hang/survive
5. Tool checks DUT state via SSH (read-only)
Пример настройки (ваши IP будут отличаться):
| Роль | IP (пример) |
|---|---|
| LAN ноутбука | 192.168.1.254 |
| WAN ноутбука | 10.0.0.211 |
| LAN DUT | 192.168.1.1 |
| WAN DUT | 10.0.0.214 |
Ключевое требование: WAN-IP ноутбука и WAN-IP DUT должны быть в одной подсети, чтобы DUT мог обращаться к ноутбуку как к вышестоящему DNS-серверу.