
Эксплойт Proof-of-concept для CVE-2022-37969 — локальное повышение привилегий в драйвере Windows Common Log File System. Демонстрирует heap spray, кражу токена и произвольную запись в ядро для получения привилегий SYSTEM.
авторы: Ricardo Narvaja и Daniel Kazimirow (Solid)
Только для демонстрационных целей. Полный эксплойт работает на уязвимых системах Windows 11 21H2.
Функциональный PoC на основе ранее опубликованной информации от Zscaler
Ознакомьтесь с подробным описанием Понимание уязвимости CVE-2022-37969 в драйвере Windows Common Log File System, локальное повышение привилегий.
Пошаговое руководство по эксплуатации:
В данном сценарии использовался Windows 11 21H2 (сборка ОС 22000.918) clfs.sys v10.0.22000.918
Первым шагом является создание файла с именем MyLog.blf в общей папке (%public%), с помощью функции CreateLogFile():



Затем он создает несколько файлов журнала со случайными именами с помощью цикла.
И внутри цикла он вызывает нашу функцию getBigPoolInfo():

Он вызывает NtQuerySystemInformation() с первым аргументом 0x42 (66 десятичное), что вернет в v5 информацию о выделениях в большом пуле (bigpool), структура которого имеет тип SYSTEM_BIGPOOL_INFORMATION.

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

v5 получит информацию о структуре SYSTEM_BIG_POOL_INFORMATION.

Количество выделений в bigpool хранится в первом поле с именем Count, во втором поле находится массив структур SYSTEM_BIGPOOL_ENTRY.

Затем мы будем искать по всем структурам тег «Clfs» и размер 0x7a00.

Он сохраняет в массиве с именем kernelAddrArray VirtualAddress, который является первым полем каждой структуры, имеющей тег CLFS и размер 0x7a00. С этого момента пулы, удовлетворяющие обоим условиям, будут называться «правильными пулами».

В дополнение к сохранению каждого правильного пула в массиве, он сохраняет последний найденный правильный пул в содержимом переменной a2, которая используется как аргумент функции.

Таким образом, a2 всегда указывает на последний созданный правильный пул с тегом CLFS и размером 0x7a00.
Переменная v26 всегда хранит предыдущий найденный правильный пул, так как она равна v24 (v26=v24) перед вызовом getBigPoolinfo(), но v24 обновляется при выходе из этого вызова последним найденным правильным пулом, а v26 остается с предыдущим найденным правильным пулом.

Затем он вычитает оба адреса, и если результат отрицательный, меняет операнды местами, чтобы он всегда был положительным.

Таким образом, в v32 будет сохранена разница между VirtualAddress последних двух найденных правильных пулов.

Затем он делает нечто подобное, в данном случае v23 изначально равен нулю, поэтому в первый раз v23=v32.

В следующий раз в цикле v23 все еще имеет то же значение и не равно нулю, поэтому он прерывается и переходит сюда.

V32 содержит последнюю разницу, а v23 предыдущую, если они равны, то выходит и увеличивает на один, но сбрасывает счетчик в ноль.
Идея состоит в том, чтобы найти 6 последовательных сравнений тегов CLFS и размера 0x7a00, разницы которых равны, и эта разница будет 0x11000. Мы увидим при выполнении, что когда будет найдено 6 (начиная с нуля) последовательных с равными расстояниями, будет получено это значение разницы между ними.

Там мы видим, что он нашел 6 последовательных и вышел из цикла создания файлов журнала.
В папке «public» мы можем увидеть созданные файлы

Наша функция craftFile() открывает исходный файл (MyLog.blf) и изменяет его для срабатывания ошибки.

После изменения файла необходимо изменить CRC32, иначе возникнет ошибка поврежденного файла.
Это значение находится по смещению 0x80C файла.