• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья CVE-2021-1732: win32kfull!xxxCreateWindowEx out-of-bounds

Azrv3l

win32kfull
Эксперт
Регистрация
30.03.2019
Сообщения
215
Реакции
539
CVE-2021-1732 - это уязвимость нулевого дня, использованная организацией BITTER APT в ходе одной операции, которая была раскрыта в феврале этого года [1] [2] [3]. Эта уязвимость использует возможность обратного вызова пользовательского режима в модуле win32kfull, чтобы прервать нормальный поток выполнения и установить флаг ошибки дополнительных данных оконного объекта (tagWND), что приводит к нарушению доступа к памяти за пределами пространства ядра.

Анализ причин
Основная причина CVE-2021-1732: В процессе создания окна (CreateWindowEx), когда объект окна tagWND имеет дополнительные данные (tagWND.cbwndExtra! = 0), указатель функции user32! _XxxClientAllocWindowClassExtraBytes, сохраненный в ntdll! _PEB.kernelCallbackTable (смещение + 0x58) в пользовательском режиме, будет вызывается через механизм обратного вызова nt! KeUserModeCallback, а системный распределитель кучи (ntdll! RtlAllocateHeap) используется для выделения дополнительной памяти данных в пользовательском пространстве. При подключении функции user32!_XxxClientAllocWindowClassExtraBytes в пользовательском режиме и изменении свойств дополнительных данных объекта окна в функции перехвата вручную атомарная операция выделения памяти для дополнительных данных в режиме ядра может быть прервана, после чего наконец, достигается возможность чтение/записи на основе дополнительной памяти данных.

Обычный процесс создания оконного объекта (CreateWindowEx) показан следующим образом (частично):

1.png


Из приведенного выше рисунка мы видим, что: когда размер дополнительных данных окна (tagWND.cbWndExtra) не равен 0, win32kfull!xxxCreateWindowEx вызывает функцию пользовательского режима user32!_XxxClientAllocWindowClassExtraBytes через механизм обратного вызова ядра, запрашивает данные памяти дополнительного окна в пользовательском пространстве. После выделения указатель выделенной памяти в пользовательском пространстве будет возвращен свойству tagWND.pExtraBytes:

2.png


Вот два режима сохранения адреса дополнительных данных tagWND (tagWND.pExtraBytes):
[Режим 1] В системной куче пользовательского пространства
Как и в обычном процессе, показанном на рисунке выше, указатель дополнительной памяти данных, выделенной в системной куче пользовательского пространства, сохраняется непосредственно в tagWND.pExtraBytes. Один макет памяти tagWND для режима 1 показан на следующем рисунке:

3.png


[Режим 2] В куче рабочего стола в пространстве ядра
Функция ntdll!NtUserConsoleControl выделяет дополнительную память данных в куче рабочего стола пространства ядра функцией DesktopAlloc, вычисляет смещение выделенного адреса дополнительной памяти данных относительно базового адреса кучи рабочего стола ядра, сохраняет смещение в tagWND.pExtraBytes и изменяет tagWND.extraFlag | = 0x800:

4.png


Один макет памяти tagWND для режима 2 показан на следующем рисунке:

5.png


Затем верните управляемое значение смещения пользовательского режима в tagWND.pExtraBytes через ntdll! NtCallbackReturn и, наконец, реализуйте возможность чтения / записи за пределами контролируемого смещения на основе базового адреса кучи рабочего стола в пространстве ядра.

Измененный процесс, который может вызвать уязвимость, показан следующим образом:

6.png


В соответствии с измененной блок-схемой выше, ключевые этапы запуска этой уязвимости объясняются следующим образом:
  1. Измените указатель функции user32! _XxxClientAllocWindowClassExtraBytes в PEB.kernelCallbackTable на пользовательскую функцию-перехватчик.
  2. Создайте несколько обычных оконных объектов и найдите адреса памяти пользовательского пространства этих объектов ядра tagWND через user32!HMValidateHandle.
  3. Уничтожьте часть обычных оконных объектов, созданных на шаге 2, и создайте один новый оконный объект с именем «hwndMagic» с указанным tagWND.cbwndExtra. HwndMagic, вероятно, может повторно использовать ранее освобожденную память оконных объектов. Следовательно, путем поиска адресов памяти пользовательского пространства ранее найденых оконных объектов с указанным tagWND.cbwndExtra в настраиваемой функции перехвата, hwndMagic может быть найден до возврата CreateWindowEx.
  4. Вызовите NtUserConsoleControl в пользовательской функции перехвата, чтобы изменить tagWNDMagic.extraFlag с флагом 0x800.
  5. Вызовите NtCallbackReturn в пользовательской функции перехвата, чтобы назначить поддельное смещение для tagWNDMagic.pExtraBytes.
  6. Вызов SetWindowLong для записи данных по адресу базового адреса кучи рабочего стола в пространстве ядра + указанного смещения, что может привести к нарушению доступа к памяти за пределами допустимого диапазона.
Реализация функции перехвата демонстрируется следующим образом:
Код:
void* WINAPI MyxxxClientAllocWindowClassExtraBytes(ULONG* size) {

    do {
        if (MAGIC_CBWNDEXTRA  == *size) {
            HWND hwndMagic = NULL;
            //search from freed NormalClass window mapping desktop heap
            for (int i = 2; i < 50; ++i) {
                ULONG_PTR cbWndExtra = *(ULONG_PTR*)(g_pWnd[i] + _WND_CBWNDEXTRA_OFFSET);
                if (MAGIC_CBWNDEXTRA == cbWndExtra) {
                    hwndMagic = (HWND)*(ULONG_PTR*)(g_pWnd[i]);
                    printf("[+] bingo! find &hwndMagic = 0x%llx in callback :) \n", g_pWnd[i]);
                    break;
                }
            }
            if (!hwndMagic) {
                printf("[-] Not found hwndMagic, memory layout unsuccessfully :( \n");
                break;
            }

            // 1. set hwndMagic extraFlag |= 0x800
            CONSOLEWINDOWOWNER consoleOwner = { 0 };
            consoleOwner.hwnd = hwndMagic;
            consoleOwner.ProcessId = 1;
            consoleOwner.ThreadId = 2;
            NtUserConsoleControl(6, &consoleOwner, sizeof(consoleOwner));

            // 2. set hwndMagic pExtraBytes fake offset
            struct {
                ULONG_PTR retvalue;
                ULONG_PTR unused1;
                ULONG_PTR unused2;
            } result = { 0 };       
            //offset = 0xffffff00, access memory = heap base + 0xffffff00, trigger BSOD   
            result.retvalue = 0xffffff00;           
            NtCallbackReturn(&result, sizeof(result), 0);
        }
    } while (false);

    return _xxxClientAllocWindowClassExtraBytes(size);
}

BSOD snapshot:

7.png


Анализ эксплойта
Из анализа первопричины мы можем увидеть, что: «Возможность чтения / записи данных по адресу, который вычисляется по базовому адресу кучи рабочего стола в пространстве ядра + указанному смещению» может быть получена через эту уязвимость.

При использовании режима ядра целью атаки является получение системного токена в целом. Общий метод показан следующим образом:
  1. Воспользуйтесь уязвимостью, чтобы получить произвольный примитив чтения / записи памяти в пространстве ядра.
  2. Утечка адреса какого-либо объекта ядра, поиск системного процесса по цепочке EPROCESS.
  3. Скопируйте токен системного процесса в токен процесса атаки, чтобы завершить задание повышения привилегий.
Препятствие - это шаг 1: как использовать «Возможность чтения / записи данных по адресу, который вычисляется по базовому адресу кучи рабочего стола в пространстве ядра + указанное смещение» для получения произвольного примитива чтения / записи памяти в пространстве ядра.

Одно из решений показано на следующем рисунке:

8.png

  1. Смещение дополнительных данных tagWNDMagic (wndMagic_extra_bytes) можно контролировать с помощью уязвимости, поэтому мы можем использовать SetWindowLong для изменения данных по указанному адресу, рассчитанному по базовому адресу кучи рабочего стола + контролируемому смещению.
  2. Используйте возможность уязвимости для изменения tagWNDMagic.pExtraBytes на смещение tagWND0 (смещение tagWND0 получается с помощью tagWND0 + 0x8), вызовите SetWindowLong, чтобы изменить tagWND0.cbWndExtra = 0x0fffffff, чтобы получить измененный tagWND0.pExtraBytes.
  3. Вычислите смещение от tagWND0.pExtraBytes к tagWND1, вызовите SetWindowLongPtr, чтобы заменить spMenu tagWND1 поддельным spMenu с помощью подделанного tagWND0.pExtraBytes, реализовать возможность произвольного чтения из памяти с помощью поддельного spMenu и функции GetMenuBarInfo. Логика GetMenuBarInfo для чтения данных по указанному адресу показана следующим образом: данные из 16 байтов сохраняются в структуре MENUBARINFO.rcBar:
    9.png
  4. Используйте измененный tagWND0.pExtraBytes, чтобы изменить tagWND1.pExtraBytes с указанным адресом, и используйте SetWindowLongPtr tagWND1, чтобы получить возможность произвольной записи в память.
  5. После получения произвольного примитива чтения / записи в память нам нужно утечь адрес объекта ядра в куче рабочего стола, чтобы найти EPROCESS. К счастью, при установке поддельного spMenu для tagWND1 на шаге 3 возвращаемое значение SetWindowLongPtr - это адрес ядра исходного spMenu, который можно использовать напрямую.
  6. Наконец, найдите системный процесс, пройдя цепочку EPROCESS, и скопируйте токен системного процесса в процесс атаки, чтобы завершить задание повышения привилегий. Этот метод относительно распространен, поэтому подробно описывать его не будем.
Последняя демонстрация повышения привилегий:

10.png


Ccылки
[1] https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-1732
[2] https://ti.dbappsecurity.com.cn/blo...-is-used-by-bitter-apt-in-targeted-attack-cn/
[3] https://www.virustotal.com/gui/file...f20dd11acd708d7db7fa37ff75bf1abfc29/detection
[4] https://en.wikipedia.org/wiki/Privilege_escalation

От ТС
Отригинал тут

Перевод:
Azrv3l cпециально для xss.pro
 

Вложения

  • 9.png
    9.png
    33.7 КБ · Просмотры: 10
Скомпилированный есть у кого?
 
Это видел, не могу собрать второй в вижуал т.к MSVC средство сборки у меня 140 версия актуальная, а во втором 120, как поставить старую версию понятия не имею, гугл что-то не помог особо
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх