Сергей Попов
Администратор
- 30.12.2015
- 6 175
- 6 946
- Специализация
- OSINT
- Веб-безопасность
- Статус верификации
- ✓ Verified
Двадцать один год. Столько command injection в
dhclient тихо лежала в кодовой базе FreeBSD, прежде чем её нашли. Когда advisory FreeBSD-SA-26:12.dhclient попал мне на стол, я перечитал описание дважды: простейший fprintf без экранирования кавычек в BOOTP-поле file, CVSS 8.1 (HIGH), CWE-149. Ни ROP-цепочек, ни heap spray, ни race condition - текстовая инъекция в lease-файл, который потом разбирает shell-скрипт от root. Уязвимость вошла в FreeBSD 6.0 в 2005 году вместе с импортом OpenBSD-реализации dhclient и пролежала до 2026-го. Ниже - root cause, патч и полная цепочка от rogue DHCP-сервера до root shell.Root cause: CWE-149 и отсутствие экранирования в dhclient
CVE-2026-42511 классифицирована как CWE-149 - Improper Neutralization of Quoting Syntax. Определение CWE звучит так: «Quotes injected into a product can be used to compromise a system. As data are parsed, an injected/absent/duplicate/malformed use of quotes may cause the process to take unexpected actions.» Применительно к dhclient: двойные кавычки из DHCP-ответа попадают в lease-файл без экранирования, ломают его синтаксическую структуру и позволяют инжектировать произвольные директивы.Корень проблемы - функция
write_client_lease() в файле sbin/dhclient/dhclient.c. При записи lease в /var/db/dhclient.leases.<if> разные поля обрабатываются по-разному, и вот тут начинается самое интересное:- Адресные поля (
fixed-address,next-server) проходят черезpiaddr(), который генерирует только валидный IP-текст - инъекция невозможна. - DHCP-опции (option 1–255) пропускаются через
pretty_print_option(), который санитизирует содержимое. - Поле
mediumзадаётся локальным администратором, не из DHCP-ответа. - А вот два поля -
lease->filenameиlease->server_name- заполняются напрямую из BOOTP-полей DHCP-ответа и записываются черезfprintf(leaseFile, " filename \"%s\";\n", lease->filename)без какой-либо санитизации.
pretty_print_option) и для адресов (написали piaddr), но BOOTP-поля остались «доверенными». Если прогнать git blame, видно, что обработка разных полей добавлялась в разное время - целостной проверки границ доверия данных никто не проводил. Классика: один разработчик экранировал своё, другой - своё, а про BOOTP-поля все решили, что «это же просто имя файла, что там может быть».Предусловия для уязвимой конфигурации:
- FreeBSD 15.0-RELEASE < p7, 14.4-RELEASE < p3, 14.3-RELEASE < p12, или 13.5-RELEASE < p13
- На системе работает
dhclient- штатная ситуация для любой FreeBSD-машины, получающей IP по DHCP - Атакующий контролирует DHCP-сервер в L2-сегменте жертвы или способен спуфить DHCP-ответы
- FreeBSD использует статическую IP-конфигурацию (dhclient не запущен)
- Патч FreeBSD-SA-26:12.dhclient уже установлен
- На коммутаторах уровня доступа включён DHCP snooping - rogue DHCP-ответы блокируются на сетевом оборудовании
- OpenBSD: уязвимость была актуальна до 2012 года, когда OpenBSD полностью отказалась от
dhclient-script, устранив вторую часть цепочки
Patch diff анализ уязвимости FreeBSD-SA-26:12
Патч адресует проблему на уровне записи: при сериализации полейfilename и server_name в lease-файл добавляется экранирование символа " (двойная кавычка) и других символов, способных нарушить синтаксическую структуру файла.Логика патча минимальна и хирургически точна: формат lease-файла не меняется, протокол DHCP не затрагивается. Единственное изменение - данные из сети перестают быть «доверенными» при записи. В
write_client_lease() прямой fprintf для полей filename / server_name заменяется на вариант с escape-обработкой. По сути - одна функция-обёртка, которая экранирует " перед записью. Патч укладывается в несколько строк. Красивое решение, если честно.Характерно, что патч не добавляет валидацию на этапе приёма DHCP-ответа (в функции разбора пакета). Санитизация происходит на уровне записи - defense in depth: даже если в будущем появится другой путь записи в lease-файл, экранирование останется.
Для сравнения: OpenBSD решила ту же проблему радикальнее - в 2012 году полностью выкинула
dhclient-script, убрав весь механизм интерпретации lease-файла через shell. FreeBSD сохраняет dhclient-script и поэтому вынуждена экранировать входные данные на каждом потенциально опасном пути. Выбор FreeBSD - минимальная правка, OpenBSD - архитектурное решение. Оба подхода закрывают уязвимость, но второй исключает весь класс атак. Я бы выбрал подход OpenBSD - зачем латать дыры, если можно убрать стену целиком.Цепочка эксплуатации FreeBSD RCE: от DHCP-пакета до root
От пакета к отравленному lease-файлу
Атакующий поднимает rogue DHCP-сервер в том же L2-сегменте, что и целевая FreeBSD-машина. Для этого хватитdnsmasq с кастомной конфигурацией или скрипта на Python с scapy для формирования DHCPOFFER. В DHCP-ответе в BOOTP-поле file подставляется payload: символ " для закрытия кавычки поля filename, ; и \n для завершения строки, и начало новой директивы medium с shell-командой.По данным AISLE (компания, обнаружившая уязвимость), когда dhclient получает такой ответ и вызывает
write_client_lease(), результат на диске выглядит так:
Код:
lease {
interface "em0";
fixed-address 192.168.1.50;
filename "";
medium ";id>/tmp/pwned";
}
filename стал пустой строкой, а инжектированная директива medium содержит shell-команду id>/tmp/pwned. dhclient при повторном разборе файла видит корректную структуру - подмена незаметна. Вот так - три символа (";\n), и lease-файл превращается в троянского коня.От lease-файла к исполнению произвольного кода
Вторая половина цепочки -/sbin/dhclient-script. Этот shell-скрипт вызывается dhclient для применения сетевой конфигурации из lease. Вызов происходит не только при первоначальном получении адреса, но и при обновлении lease (RENEW, REBIND) - у атакующего множественные окна для срабатывания.Из описания NVD: «When the lease file is subsequently re-parsed by dhclient, e.g., after a system restart, an attacker-controlled field from the lease is passed to dhclient-script(8), which evaluates it.» Значение директивы
medium из lease-файла подставляется в контекст, где shell интерпретирует его - инжектированная команда выполняется с правами root. dhclient работает от root не только при загрузке, но и при каждом обновлении lease в ходе нормальной работы сети.Цепочка целиком:
- Rogue DHCP-сервер отправляет ответ с инъекцией в поле
file - dhclient записывает отравленный lease в
/var/db/dhclient.leases.<if> - При следующем вызове dhclient-script (renewal, перезагрузка, повторный DHCP-цикл) команда исполняется от root
sh -i, запись SSH-ключа в /root/.ssh/authorized_keys, тихое добавление пользователя. По оценке AISLE, уязвимость «trivially weaponizable and wormable» - для wormable-варианта payload поднимает rogue DHCP на скомпрометированной машине и распространяет себя на соседние FreeBSD-хосты в сегменте. Червь на стероидах, который распространяется через штатный сетевой протокол.Принципиальное отличие от memory corruption RCE: эксплойт полностью детерминистичен. Нет зависимости от ASLR, stack canaries, или раскладки кучи. Payload - обычный текст, не бинарный шеллкод. Надёжность - практически 100% при контроле DHCP-трафика жертвы. Это не «попробуй 50 раз и может сработает» - это «отправил пакет, получил root».
Поверхность атаки и место в kill chain
CVSS-вектор CVE-2026-42511:[URL='https://nvd.nist.gov/vuln/detail/CVE-2026-42511']CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H[/URL] - 8.1 HIGH. Разбор компонентов: AV:N - атака по сети через rogue DHCP; AC:H - необходимо контролировать DHCP-трафик (позиция в одном L2-сегменте или ARP spoofing); PR:N - аутентификация не требуется, DHCP не предусматривает авторизацию сервера; UI:N - жертва просто запускает dhclient при подключении к сети; C:H/I:H/A:H - полная компрометация с root shell.По данным CISA Vulnrichment (SSVC): Exploitation -
none (эксплуатация в дикой природе не зафиксирована), Automatable - no, Technical Impact - total. EPSS = 0.0043 (перцентиль 0.3519, ниже медианы) - вероятность массовой эксплуатации в ближайшие 30 дней оценивается невысоко. Но для целевой атаки на конкретный FreeBSD-хост - всё, что нужно.В терминах MITRE ATT&CK уязвимость покрывает:
- Exploitation for Client Execution (T1203, Execution) - dhclient как клиент обрабатывает данные от сервера
- Unix Shell (T1059.004, Execution) - dhclient-script это shell-скрипт, исполняющий инжектированную команду
- Exploit Public-Facing Application (T1190, Initial Access) - для случая, когда dhclient слушает DHCP из недоверенного сегмента
FreeBSD, по данным AISLE, работает на серверах Netflix Open Connect, NetApp, Citrix NetScaler, а также лежит в основе PlayStation OS. Сценарии атаки: внутренний пентест (атакующий в корпоративном VLAN с FreeBSD-серверами), Wi-Fi в публичном месте (rogue AP с DHCP → root на FreeBSD-ноутбуке), компрометация DHCP-relay для атаки на удалённые сегменты.
Воспроизведение эксплойта FreeBSD на стенде
Требования к окружению
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Разворачиваем FreeBSD-VM, настраиваем DHCP-клиент. На VM атакующего конфигурируем rogue DHCP-сервер с payload в BOOTP file field: строка, закрывающая кавычки
filename, вставляющая ;\n, и открывающая директиву medium с shell-командой. Для dnsmasq payload задаётся через опцию dhcp-boot; для scapy - прямое формирование DHCP-пакета с нужным содержимым поля file.После отправки rogue DHCP-ответа и получения его dhclient на стороне жертвы - проверяем lease-файл:
Код:
grep medium /var/db/dhclient.leases.em0
medium с вашей командой подтверждает успешную инъекцию. Дальше - дождаться вызова dhclient-script при renewal или инициировать перезагрузку, затем проверить результат (ls -la /tmp/pwned или наличие SSH-ключа в /root/.ssh/authorized_keys).Ограничения при воспроизведении. В сетях с DHCP snooping (Cisco, Juniper, Arista) rogue DHCP-ответы блокируются на коммутаторе - техника неприменима без предварительной компрометации сетевого оборудования. При наличии легитимного DHCP-сервера rogue должен ответить быстрее (race по скорости). Митигации памяти (ASLR, stack canaries) не имеют значения: это текстовая инъекция, не memory corruption.
Детектирование и митигация CVE-2026-42511
Чеклист для сисадмина:- Обновиться:
freebsd-update fetch install, затем перезапустить dhclient. Целевые версии: 15.0-RELEASE-p7, 14.4-RELEASE-p3, 14.3-RELEASE-p12, 13.5-RELEASE-p13 или новее. - Проверить lease-файлы на следы эксплуатации: директива
medium, которую администратор не задавал вручную, может указывать на состоявшуюся атаку. Прогонитеgrep -r medium /var/db/dhclient.leases.*- если нашли что-то незнакомое, у вас проблемы посерьёзнее патча. - Включить DHCP snooping на коммутаторах уровня доступа - не замена патча, но существенное сужение attack surface.
- Для серверов со статическим IP: не запускать dhclient. Полностью закрывает вектор.
- Настроить integrity monitoring для файлов
/var/db/dhclient.leases.*- черезauditdили file integrity checker. - Если немедленное обновление невозможно - временный workaround: отключить dhclient, назначить IP статически.
", ;, \n - прямой индикатор попытки эксплуатации CVE-2026-42511.CVE-2026-42511 обнаружена AISLE в рамках координированного раскрытия, включавшего также FreeBSD-SA-26:15.dhclient и FreeBSD-SA-26:16.libnv - при обновлении проверьте патчи для всех трёх advisory.
Для сравнения с другой свежей FreeBSD RCE: CVE-2026-4747 (CWE-121, stack-based buffer overflow в kgssapi.ko, CVSS 8.8 HIGH) - классический memory corruption в модуле ядра, требующий ROP-цепочек, многопакетной доставки шеллкода и перехода из ядра в userland. По данным публикации Calif, разработка эксплойта для CVE-2026-4747 заняла ~4 часа даже с помощью LLM. CVE-2026-42511 эксплуатируется за минуты при наличии готового rogue DHCP - никакого бинарного exploitation, только текстовая инъекция через отсутствие экранирования. Разница как между хирургической операцией и открыванием незапертой двери.
Двадцать один год в кодовой базе - и ноль алертов за всё время. Это ставит вопрос не к конкретному коммиттеру, а к системе аудита legacy-кода как таковой. Уязвимость тривиальна:
fprintf без экранирования кавычек, который прочитает и поймёт каждый, кто видел C. Не нужен фаззер, не нужен символьный исполнитель - достаточно пройтись grep по дереву исходников и спросить: «Это поле приходит из сети? Оно экранируется перед записью?»CWE-149 - один из самых редких классов в каталоге CWE, и аудиторы целенаправленно его не ищут. Все фокусируются на buffer overflow, use-after-free, race condition - классика binary exploitation. А command injection через текстовый формат, где данные из сети записываются в конфиг и конфиг потом интерпретируется привилегированным shell-скриптом, остаётся в слепой зоне. Паттерн «принять данные из сети → записать в файл → разобрать другим процессом с привилегиями» встречается в Unix повсеместно: dhclient, различные *-script обёртки, cron-задачи, генерируемые из внешних данных, auto-generated конфиги демонов.
После публикации CVE-2026-42511 начнётся ревизия аналогичных паттернов в других BSD-подсистемах. Если вы занимаетесь vulnerability research - прогоните по дереву исходников FreeBSD поиск
fprintf с %s внутри кавычек, где источник строки - сетевые данные. С высокой вероятностью найдёте ещё не один незакрытый путь инъекции. Если хочешь отработать саму цепочку DHCP injection на живом стенде - на HackerLab есть таски по network-level exploitation, где подобные примитивы собираются руками от начала до конца.