
Удаленный эксплойт для Windows Network File System CVE-2022-30136
автор: Ricardo Narvaja
Только для демонстрационных целей. Полный эксплойт работает на уязвимых системах Windows Server.
Ознакомьтесь со статьей Анализ CVE-2022-30136 «Уязвимость Windows Network File System».
Я хотел написать эту статью, чтобы продемонстрировать анализ, который я провел при разработке эксплойта Core Impact «Windows Network File System Remote», использующего уязвимость CVE-2022-30136.
Уязвимость удаленного выполнения кода в Windows Network File System представляет собой ошибку вычисления размера, которая возникает при создании ответа сервера в COMPOUND REQUEST с использованием версии 4.1 NFS.
Сервер вычисляет размер пула меньше необходимого, а затем при копировании данных для формирования ответа происходит переполнение буфера.
Функция Nfs4SvrXdrpGetEncodeOperationResultByteCount в nfssvr.sys вызывается для каждой операции и возвращает размер, который меньше необходимого (на 4 байта меньше для каждой операции).
Было выпущено исправление для Nfs4SvrXdrpGetEncodeOperationResultByteCount.
Эта функция вызывается во время каждой ОПЕРАЦИИ COMPOSE REQUEST, чтобы вернуть количество байтов, необходимых для каждой из них, на основе OPCODE. Затем это значение добавляется к заголовку и другим частям ответа. После этого вычисляется окончательный размер всего ответа для выделения памяти, и в него происходит копирование для ответа.
В каждом случае видно, что значение размера, возвращаемое для каждой операции, в уязвимой версии на четыре байта меньше, чем в исправленной.
Я собрал POC для Windows Server 2019.
Ниже показана уязвимая версия nfssvr.sys, использованная в этом POC, а затем исправленная версия для Windows Server 2019:

Следующее изображение показывает CASE 26 в различиях:

В примере CASE 26 видно, что константа, добавляемая к вычисленному значению, равна 0x2c в уязвимой версии и 0x30 в исправленной.
То же самое наблюдается в каждом случае, соответствующем каждому OPCODE. Уязвимая версия всегда возвращает размер на четыре байта меньше, чем исправленная.
Мы не будем показывать все случаи, так как исправление аналогично для всех OPCODE.
Родительской функцией для Nfs4SvrXdrpGetEncodeOperationResultByteCount является Nfs4SvrXdrEncodeCompoundResults. Она считывает количество операций, отправленных в COMPOUND REQUEST.
В этом POC значение равно 0x34 (52d). Когда мой POC подключается к серверу на порт 2049 (порт по умолчанию для NFS), мне нужно установить условную точку останова для остановки.


В данном случае остановка происходит, когда number_of_operations=0x34.

Здесь выделяется пул с тегом ARGS.

Затем я создам структуру с именем TAG_ARGS_0x10e0 для обратного проектирования полей.

Она копирует number_of_operations в r13 и выполняет цикл по уязвимой функции один раз на каждую операцию, пока счетчик не достигнет значения r13.

Показано, что первый package_OPCODE = 0x35, что соответствует SEQUENCE в первой обязательной операции COMPOUND REQUEST. На изображении ниже стрелка указывает на этот OPCODE в моем пакете.

Здесь показаны аргументы уязвимой функции.


Внутри уязвимой функции она считывает OPCODE и переходит к соответствующему CASE.

Из исходного значения OPCODE (53) вычитается три.

И переходит к CASE 50, возвращая 0x28 для необходимого размера этой операции.


В различиях видно, что исправленная версия возвращает 0x2c.

Это возвращаемое значение добавляется к предыдущему значению других полей ответа для вычисления размера операций. В данном случае это значение равно 0X40c.

Ниже показано, как значения складываются:

При выходе из цикла вычисляется общий размер. В данном случае общий размер равен 0x1310.

Можно предположить разницу между уязвимой и исправленной версиями, вычислив размер по формуле: number_of_operations * 4.
В данном случае выделение в исправленной версии будет на 0x34 * 4 = 0x68 больше, чем в уязвимой.

После этого добавляется 0x24. Это значение вычисляется аналогичным образом как в уязвимой, так и в исправленной версиях.

Затем в обоих случаях добавляется константа 0xf.

До этого момента размер в этом примере составлял 0x1340.

Затем вызывается rpcxdr_OncRpcBufMgrpAllocate.

Затем переходит к r15.


Вычитается единица и добавляется четыре. Затем сравнивается с 0x800.
Этот неправильно вычисленный размер используется только если он больше 0x800. По этой причине только COMPOUND REQUEST вызовет ошибку.

Сначала выделяется пул размером = 0x80 с тегом XdBD.

Наконец, здесь выделяется пул для ответа размером 0x1398, добавляются некоторые константные значения.

Затем выделяется 0x13a0 (включая тег XdBP и заголовок).

Оттуда адрес нового выделенного пула сохраняется в поле: tag_XdBD_0x80.p_TAG_XDBP_0x13a0.

Это указывает на адрес ответа, в который постоянно происходит копирование.

Затем начинается формирование заголовка ответа.

Ниже приведен пример того, как данные сохраняются в содержимое временного указателя, и к нему добавляется четыре.


Ниже показано, как происходит копирование в содержимое адреса ответа.

Записывается первое двойное слово, и указатель увеличивается на четыре.

Затем записывается второе двойное слово и добавляется четыре.


После выхода из функции весь заголовок записан.

После этого возвращается в nfssvr.sys для продолжения записи ответа.

Продолжается декодирование и запись в ответ, добавление четырех к временному указателю.

Когда заголовок завершен, достигается этот цикл для записи всех операций. Начинается с первого OPCODE 0x35.


Видно, что записывается 0x428 от начала пула.

Теперь указатель находится после тега.


Установив здесь точку останова, можно увидеть, как были записаны все операции.


После выхода из цикла все операции скопированы.

Проверим конец пула.

Там видна запись за пределами.

Выделение меньше, чем скопированные данные, что приводит к переполнению пула.
Это вызывает BSOD на целевой машине. Однако возникает вопрос: можно ли добиться удаленного выполнения кода или "запись что куда"?
Я пробовал различные комбинации опкодов, чтобы получить ответ с контролируемыми данными в переполненных байтах. К сожалению, мне не повезло.
Максимальный тег (контролируемый мной) можно разместить только в начале, и его максимальный размер составляет 0x400.

Все остальные опкоды, которые я пробовал, не возвращают контролируемые данные. Следовательно, я считаю, что это невозможно или, по крайней мере, чрезвычайно сложно получить RCE или повысить привилегии с помощью этой ошибки. Тем не менее, это всё ещё может быть возможно, так как я не пробовал все комбинации среди огромного количества существующих возможностей.
Для сборки POC я попробовал клиент с именем «NFS CLIENT». Он поддерживает NFS 4.1, и я смог опробовать различные опкоды, копируя файлы, редактируя, создавая папки и т.д.

В этой сборке я смог создать образец пакета COMPOUND и настроить размер, идентификатор клиента, идентификатор сессии и т.д.

Затем я отправил EXCHANGE_ID, чтобы получить идентификатор клиента, использовал его для отправки CREATE_SESSION и, наконец, большой COMPOUND REQUEST.

На этом этапе ошибка эксплуатируется, что приводит к удаленному выполнению кода и позволяет осуществить DoS-атаку.
Надеемся, это было полезно. Если у вас есть вопросы, обращайтесь к нам по адресу [email protected].
Приятного использования!