Хабрахабр

Как изучение критической уязвимости DHCP в Windows 10 привело к обнаружению еще двух ошибок безопасности

Изображение: Unsplash

А в некоторых случаях таких новых уязвимостей оказывается больше одной. Как было описано в предыдущей статье про CVE-2019-0726, иногда поиск деталей об уже известной уязвимости приводит к обнаружению новой уязвимости.

Как всегда происходит при поиске уязвимостей, даже если важные выводы в конце сводятся к одной-двум функциям, в процессе разбора приходится просмотреть гораздо большее количество кода. В статье рассматривались две функции библиотеки dhcpcore.dll: вскользь упомянутая UpdateDomainSearchOption и более подробно разобранная вызываемая ею DecodeDomainSearchListData. Пусть в данный момент нет времени обращать на них внимание, но такие мелочи откладываются на подкорке и, если по истечении некоторого срока появляется возможность вернуться к ним и проверить свои догадки, вновь всплывают в сознании. И порой глаз цепляется за мелочи, которые не имеют отношения к текущей задаче, но могут иметь самостоятельное значение или пригодиться позже.

При изучении функции DhcpExtractFullOptions, отвечающей за обработку всех опций, заданных в DHCP-ответе от сервера, в частности вызывающей UpdateDomainSearchOption, внимание сразу привлекают два массива на стеке по 256 элементов каждый: Так и произошло на этот раз.

Так как в тот момент мы разбирали другую уязвимость, эта информация к делу не относилась. При этом не заметно присутствия каких-либо проверок, ограничивающих значения итераторов данных массивов. Поэтому оставалось лишь запомнить это место в коде, чтобы возвратиться к нему позже.

Анализ

Проходит пара недель, и мы вновь вспоминаем про обратившую на себя внимание ранее функцию DhcpExtractFullOptions. Обращаемся к ней в дизассемблере, причесываем ранее не до конца разобранные куски кода и пытаемся понять, для чего используются два заинтриговавших нас статических массива.

В самом начале исполнения функции массивы и их итераторы обнуляются:

Помимо этого, по результатам разбора она также записывает соответствующее событие в сервис ETW (Event Tracing for Windows). Функция занимается разбором всех опций в полученном от DHCP-сервера пакете, сбором информации из них и ее последующей обработкой. Вместе с большим количеством других данных они передаются в процедуру EtwEventWriteTransfer. Именно в логировании события и принимают участие интересующие нас буферы. Работа по подготовке всех данных для логирования довольно объемна и не имеет большого значения для рассматриваемой нами уязвимости, поэтому обойдемся без иллюстраций.

Происходит заполнение в цикле разбора опций. Важнее определить, как эти буферы заполняются. Сначала для текущей поступившей на обработку опции вызывается функция с говорящим названием ParseDhcpv4Option, которая либо заполняет поля объекта dhcp_pointers на основании поступивших данных, либо делает пометку о незнакомой опции, когда встречает идентификатор опции со значением, для которого отсутствует обработчик.

Если функция встретила незнакомую опцию и, соответственно, не выставила флаг is_known_option, то значение идентификатора записывается также и в следующий элемент второго массива — unknown_tags. По возвращении из ParseDhcpv4Option значение идентификатора текущей опции option_tag записывается в следующий элемент массива all_tags, первого из интересующих нас массивов. Естественно, осмысленные названия переменные в этой статье получили уже по результатам разбора кода.

При этом проверка значений индексов этих массивов отсутствует вовсе. Таким образом, массив all_tags хранит теги всех опций из поступившего сообщения, а массив unknown_tags — теги только для незнакомых парсеру опций. Для переполнения первого массива достаточно отправить от DHCP-сервера пакет с количеством опций, превышающим 256. Следовательно, значения таких индексов могут превышать 256 и приводить к записи за пределы отведенной на стеке под массивы памяти. То же самое справедливо и для второго массива с той лишь разницей, что отправлять следует опции, которые клиент не умеет обрабатывать.

Эксплуатация

Попробуем теперь на практическом примере убедиться в том, что сделанные нами выводы верны. Для начала обратим внимание на то, что теги опций занимают один байт, в то время как элементы массивов имеют тип int, то есть являются четырехбайтовыми. Таким образом, мы имеем переполнение, в котором мы контролируем каждый четвертый байт, а остальные при перезаписи обнуляются.

Смоделируем ситуацию, в которой DHCP-сервер отправляет достаточное для перезаписи количество опций. Для проверки нашего предположения проще всего будет перезаписать хранящуюся на стеке security cookie рассматриваемой функции, что вызовет исключение, связанное с проверкой безопасности. Таким образом, каждая опция занимает два байта, и полный размер пакета со всеми заголовками составит 1100—1200 байт. Пускай это будут 0x1a0 (416) опций с идентификатором 0xaa и нулевым размером. Это значение находится в пределах MTU для Ethernet, следовательно, имеются основания полагать, что сообщение не будет фрагментировано, что позволит нам избежать возможных неблагоприятных эффектов.

Отправляем сформированный описанным способом пакет в ответ на запрос от DHCP-клиента и перехватываем на клиентской машине исключение в соответствующем процессе svchost.exe:

Как видно из трассировки стека, идентификаторами опций из нашего пакета были переписаны и stack cookie, и адрес возврата из функции.

На современных системах переполнение буфера на стеке является довольно сложной и трудоемкой в эксплуатации уязвимостью благодаря всем существующим нынче защитным механизмам. Конечно, создание рабочего эксплойта под данную ошибку потребует от злоумышленника достаточно больших усилий. Они, например, никак не могут помочь против перезаписи хранящихся на стеке между переполняемым буфером и адресом возврата локальных переменных. С другой стороны, не следует забывать, что все эти механизмы либо защищают от перезаписи адреса возврата и обработчиков исключений, либо запрещают исполнение кода в непредназначенных для этого регионах памяти, либо мешают предсказывать адреса. И рассматриваемая функция DhcpExtractFullOptions содержит в этом интервале несколько потенциально опасных переменных.

После непродолжительной переписки и занявшего примерно неделю анализа заявки получаем ответ, что для описанной уязвимости готовится CVE-идентификатор, исправление планируется к выпуску в марте, а информация об уязвимости уже имеется в Microsoft, была сообщена кем-то ранее. Вновь пишем в Microsoft об обнаруженной ошибке. Факт, вообще говоря, неудивительный, ведь ошибка лежит буквально на поверхности, а буферы, не содержащие граничных проверок индексов, всегда обращают на себя внимание первыми и часто могут быть обнаружены автоматическими средствами анализа.

Исследователем, сообщившим информацию ранее, оказался Mitch Adair, тот самый сотрудник Microsoft, что обнаружил и исправленную в январе DHCP-уязвимость CVE-2019-0547. В марте, как и было заявлено, выходит обновление, исправляющее описанную ошибку, получившую идентификатор CVE-2019-0697.

Автор: Михаил Цветков, специалист отдела анализа приложений Positive Technologies.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»