понедельник, 24 октября 2011 г.

MS11-077

Уязвимость в графической подсистеме windows, в win2k.sys, сидит там с момента выхода windows 2000, т.к. именно в этой версии винды появилась CB_ADDSTRING message и следовательно обработка этой мессаги в ядре, которая имеет в себе баг.

BF91452C ; __stdcall NtUserfnINCBOXSTRING(x, x, x, x, x, x, x)
BF91452C arg_0           = dword ptr  8
BF91452C arg_4           = dword ptr  0Ch
BF91452C arg_8           = dword ptr  10h
BF91452C arg_C           = dword ptr  14h
BF91452C arg_10          = dword ptr  18h
BF91452C arg_14          = dword ptr  1Ch
BF91452C arg_18          = dword ptr  20h
BF91452C
BF91452C                 mov     edi, edi
BF91452E                 push    ebp
BF91452F                 mov     ebp, esp
BF914531                 mov     ecx, [ebp+arg_0] <=== не проверяется на валидность, прилетает переданное значение 0xFFFFFFFF
BF914534                 mov     eax, [ecx+20h] <=== oops! BSOD

Находится данная ф-ция в табличке и вызывается ф-цией NtUserMessageCall по индексу(CB_ADDSTRING = 0x143):

NtUserMessageCall(...):
{
...
    BF80EF21                 push    [ebp+arg_18]    ; int
    BF80EF24                 movzx   eax, ds:_MessageTable[eax]
    BF80EF2B                 push    ecx             ; int
    BF80EF2C                 push    [ebp+arg_10]    ; int
    BF80EF2F                 and     eax, 3Fh
    BF80EF32                 push    [ebp+Address]   ; Address
    BF80EF35                 push    [ebp+UnicodeString] ; int
    BF80EF38                 push    [ebp+arg_4]     ; int
    BF80EF3B                 push    esi             ; int
    BF80EF3C                 call    ds:_gapfnMessageCall[eax*4]
...
}

BF991428 _gapfnMessageCall:
..,.
BF991494                 dd offset _NtUserfnINCBOXSTRING@28 ;
....

Таким образом, можно поймать BSOD, вызвав:

NtUserMessageCall( (HWND)-1,CB_ADDSTRING, 0, 0, 0, 0, FALSE );
или  
SendMessageCallback((HWND)-1,CB_ADDSTRING,0,0,0,0);

Дальнейшая эксплуатация на первый взгляд возможна, для этого нужно создать свой объект HWD в страничке выделенной в UM по нулевому адресу, причем сформировать таким образом, чтобы передалось управление на один из колбеков в этой структуре. 

Updated: Crash провел более детальный ресерч(см. комменты) и согласно ресерчу, уязвимость не эксплуатируемая.

6 комментариев:

  1. Так она ведь даже не эксплуатируемая, local DoS only... Из всей пачки закрытых в MS11-077 CVE-шек ты почему-то выбрал самую унылую.

    ОтветитьУдалить
  2. Помоему вполне себе эксплуатируемая, выделяем память по нулевому адресу, формируем объект там, перезаписываем внутренние указатели, ждем или сами инициируем их вызов, получаем управление в ядре. Трудоемко, но выполнимо помоему.

    ОтветитьУдалить
  3. То, как писать эксплойты для NULL pointer dereference -- я таки знаю, но по помотри на win32k!xxx* функции, которые вызываются в процессе обработки сообщения из NtUserfnINCBOXSTRING/NtUserfnINLBOXSTRING -- в них везде есть проверки на HWND_BROADCAST

    ОтветитьУдалить
  4. Непонятно про какие проверки речь и как они помогут, если объект контролируется атакующим.

    ОтветитьУдалить
  5. Да открой ты отладчик, и сделай нормальный control flow analysis, наконец. Эта уязвимость - не эксплуатируемая, если я не прав, то попробуй взять и написать работающий LPE эксплойт под неё.

    Все NtUser* системные вызовы, которые принимают в качестве аргументов
    дескриптор окна, проверяют его на валидность, при этом (HWND)(-1) (он же
    HWND_BROADCAST) так же считается валидным дескриптором и используется,
    например, для отправки оконного сообщения всем окнам window station-а.

    Функции, которые вызываются из NtUserMessageCall, ожидают получить на
    вход валидный указатель на структуру объекта окна (ведь валидация
    происходит в самом NtUserMessageCall), однако, некоторые из них не
    ожидают получить вместо валидного указателя HWND_BROADCAST, из-за чего
    аварийно завершают работу системы, при попытке интерпретировать
    HWND_BROADCAST как указатель на структуру окна.

    К таким уязвимым функциям относятся NtUserfnINCBOXSTRING и
    NtUserfnСNCBOXSTRING. Далее я буду рассматривать code flow для первой,
    поскольку они практически идентичны.

    В зависимости от входных параметров из NtUserfnINCBOXSTRING могут быть
    вызваны следующие цепочки функций:

    1) xxxWrapSendNotifyMessage
    2) NtUserfnINSTRINGNULL -> xxxSystemBroadcastMessage
    3) NtUserfnINSTRING -> xxxSystemBroadcastMessage

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

    Цепочка вызовов, которая начинаяется с xxxWrapSendNotifyMessage,
    выглядит следующим образом:

    xxxWrapSendNotifyMessage -> xxxSendNotifyMessage ->
    xxxSendMessageCallback -> xxxSystemBroadcastMessage

    Как видно, она заканчивается на той же самой xxxSystemBroadcastMessage,
    которая отбрасывает наш HWND_BROADCAST.

    Таким образом, единственное что может сделать атакующий -- это Local DoS
    в следствии того, что функция NtUserfnСNCBOXSTRING совершает манипуляции
    с указателем на структуру окна, не проверяя этот указатель на
    HWND_BROADCAST.

    Во всех остальных функциях вызывающихся из NtUserfnСNCBOXSTRING, которые
    упоминались выше, корректные проверки на HWND_BROADCAST
    присутствуют.

    ОтветитьУдалить
  6. >Да открой ты отладчик, и сделай нормальный >control flow analysis, наконец.
    Мой интерес к ней давно потерян, увы.

    >Эта уязвимость - не эксплуатируемая
    ok

    Спасибо за ресерч.

    ОтветитьУдалить