
Удаленный эксплойт для 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.
