Мировая общественность всполошилась после заявления "эксперта" FOON о том, что все члены семейства Windows содержат неисправимую Design Error, могущую привести к локальной эскалации привелегий вплоть до LocalSystem. Однако НИКАКИЕ Windows Messages НЕ ПРИВОДЯТ к выполнению произвольного кода "сами по себе", в том числе, упомянутый в эксплоите WM_TIMER, который в качестве параметра может принимать адрес любой процедуры.
"Сикретный Огент", sikogent@mail.ru
Мировая общественность всполошилась после заявления "эксперта" FOON о том, что все члены семейства Windows содержат неисправимую Design Error, могущую привести к локальной эскалации привелегий вплоть до LocalSystem.
http://www.void.ru/content/994
http://www1.xakep.ru/post/16039/default.asp
http://securitylab.ru/?ID=32281
По мнению FOON'а, посылка определенных Windows Messages может привести к выполнению произвольного кода в контексте другого приложения, в том числе, сервиса, запущенного с правами LocalSystem, и это является ошибкой класса Design Error, т.к. проблема вызвана неспособностью отличить сообщение, посланное системой, от сообщения, посланного "зловредным" приложением.
Однако, давайте разберемся. Для начала, НИКАКИЕ Windows Messages НЕ ПРИВОДЯТ к выполнению произвольного кода "сами по себе", в том числе, упомянутый в эксплоите WM_TIMER, который в качестве параметра может принимать адрес любой процедуры.
Проверить это можно с помощью простенькой программы:
int x(){ printf("Exploited!\n"); } int main(){ PostMessage(GetActiveWindow(),WM_TIMER,0,(long)&x); for(;;) }Запустив эту программу, мы не увидим сообщения "Exploited". Почему? Потому что реакция на сообщение WM_TIMER, так же, как и на любые другие Windows Messages, производится из функции DispatchMessage, которой в нашей программе нет.
А вот как может выглядеть программа, реагирующая на WM_TIMER:
int main(){ MSG msg; PostMessage(GetActiveWindow(),WM_TIMER,1,(long)&x); printf("WM_TIMER=%d addr(x)=%x\n",WM_TIMER,(long)&x); for(;;){ GetMessage(&msg,GetActiveWindow(),0,65535); printf("got WM=%d wparam=%x lparam=%x\n",msg.message,msg.wParam,msg.lParam); DispatchMessage(&msg); printf("dispatched\n"); } }Запустив ее, мы получим:
WM_TIMER=275 addr(x)=401005 got WM=275 wparam=1 lparam=401005 Exploited! dispatchedПервая строка показывает, что сообщение WM_TIMER имеет код 275, а адрес процедуры x() - 401005. Далее видно, что срабатывает функция GetMessage, а затем выводится строка "получено сообщение с кодом 275, первый параметр - 1, второй параметр - 401005. Далее вызывается функция DispatchMessage, и, очевидно, уже из нее происходит вызов x(), нарисовавшей "Exploited".
Совершенно очевидно, что нет никаких проблем программно отфильтровать любые "левые" сообщения, например, вот так:
for(;;){ GetMessage(&msg,GetActiveWindow(),0,65535); printf("got WM=%d wparam=%x lparam=%x\n",msg.message,msg.wParam,msg.lParam); if((msg.message==WM_TIMER) && (msg.lParam!=USED_TIMER)){ printf("Hehe. Coolhatsking attempt!\n"); continue; } DispatchMessage(&msg); printf("dispatched\n"); }И вместо "Exploited" мы получим милую фразу "Hehe. Coolhatsking attempt!"...
Является ли это новостью? Нет. Microsoft документировала это еще 5 лет назад:
http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0397/hood/hood0397.htm&nav=/msj/0397/newnav.htm
Очевидно, что проблема не столько в самой организации Windows Messages, сколько в незнании механизмов ее работы как у авторов некоторых приложений, оказавшихся уязвимыми, так и у некоторых "security experts".
Первое — находим постоянно, второе — ждем вас