Рис. 1. Ушиблен, но не сломлен. Калькулятор Windows, чей код недавно опубликован на Github, оказался одним из двух протестированных приложений, которые не зависли и не упали в противостоянии с фаззером оконных сообщений разработки 2000 года. Размер окна специально увеличен, чтобы показать артефакты фаззинга

Настало время для второй части наших усилий по проверке древних методов фаззинга на современных системах. Если вы пропустили, вот первая часть. На этот раз мы опробуем на Windows 10 методы фаззинга из статьи «Эмпирическое исследование надёжности приложений Windows NT с использованием случайного тестирования» (она же «отчёт по фаззингу NT») Джастина Форрестера и Бартона Миллера, опубликованной в 2000 году.

Исследователи протестировали 33 приложения Windows NT и ранней версии Windows 2000 на восприимчивость к искажённым оконным сообщениям и случайным событиям мыши и клавиатуры. Поскольку д-р Миллер опубликовал код фаззера, мы использовали в точности те же инструменты, что и первоначальные авторы, для поиска ошибок в современных приложениях Windows.

Результаты почти идентичны: 19 лет назад 100% протестированных приложений вылетели или зависли, встретив искажённые оконные сообщения. Сегодня тот же фаззер уронил или повесил 93% протестированных приложений. Устояли только два, в том числе наш старый знакомый Калькулятор (рис. 1). Мы также нашли ошибку (но не проблему безопасности) в Windows.

Краткое введение в Windows


Итак, что такое оконные сообщения и почему они вызывают сбой программы?

Приложения Windows с графическим интерфейсом управляются событиями: движения мыши, нажатия кнопок, нажатия клавиш и т. д. Приложение, управляемое событиями, ничего не сделает, пока не получит событие. Как только событие получено, приложение выполняет действие на основе события, а затем ожидает других событий. Звучит знакомо? Эта архитектура получила вторую жизнь в таких платформах, как node.js.

Оконные сообщения — это метод уведомления о событиях в Windows. У каждого из них есть числовой код, связанный с конкретным событием. У каждого сообщения один или несколько параметров, которые по соглашению называется lParam и wParam. Они определяют более подробную информацию о событии. Примеры такой информации — координаты перемещения мыши, какая клавиша нажата или какой текст вывести в окне. Эти сообщения может отправить сама программа, операционная система или другие программы. Они могут прибыть в любое время и в любом порядке и должны быть обработаны приложением с получающей стороны.

Последствия для безопасности


До Windows Vista процесс с низким уровнем привилегий мог отправить сообщение процессу с высокими привилегиями. Используя правильную комбинацию сообщений, можно выполнить код в том процессе. В системе Vista от подобных «подрывных атак» удалось в значительной степени защититься с помощью UIPI и путём изоляции системных служб в отдельном сеансе.

Неправильная обработка оконных сообщений вряд ли окажет влияние на безопасность современных систем Windows по двум причинам. Во-первых, оконные сообщения нельзя отправить по сети. Во-вторых, сбой приложения или выполнение кода на том же уровне привилегий, не очень полезно злоумышленнику. Вероятно, авторам доклада по фаззингу NT это было очевидно. Они не делают заявлений о безопасности, но правильно указывают, что сбои при обработке оконных сообщений подразумевают отсутствие строгого тестирования.

Есть некоторые области, где выполнение кода с одинаковыми привилегиями способно нарушить безопасность. Некоторые приложения объединяют различные примитивы безопасности для создания искусственного уровня привилегий, изначально отсутствующего в операционной системе. Типичный пример — песочница для рендеринга в браузере. Производители браузеров хорошо осведомлены об этих проблемах и приняли меры для их устранения. Другой пример — антивирусные продукты. Там панель управления работает с нормальными привилегиями, но изолирована от других модулей антивируса.

Методика тестирования


Для фаззинга всех приложений в тестовом наборе мы использовали тот же основной код и методику фаззинга, описанные в первоначальном отчёте по NT. В частности, в обоих режимах SendMessage и PostMessage фаззер использовал три итерации по 500 000 сообщений с сидом 42 и три итерации по 500 000 сообщений с сидом 1,337. Результаты появились после выполнения только одной итерации каждого метода.

Случайный ввод с мыши и клавиатуры мы пропустили из-за ограничений по времени и желания сосредоточиться исключительно на оконных сообщениях. Мы также призываем желающих повторить тестирование и подтвердить результаты.

Подводные камни


Для работы фаззера в Windows 10 пришлось внести два незначительных изменения. Во-первых, адаптировать его для 64-битной платформы. Второе изменение позволило фаззеру выбирать определённый дескриптор окна с помощью аргумента командной строки. Фаззинг конкретного дескриптора — быстрое решение проблемы с фаззингом приложений Universal Windows Platform (UWP). Оригинальная программа ориентирована на фаззинг окон, принадлежащих определённому процессу, но все приложения UWP отображают свой пользовательский интерфейс через тот же процесс (рис. 2). Это означает, что фаззер нельзя направить на главное окно приложений UWP.


Рис. 2. На платформе UWP все приложения принадлежат одному процессу (ApplicationFrameHost.exe). Для фаззинга этих приложений пришлось изменить оригинальный фаззер NT и направить его на конкретные дескрипторы окон

При модификации фаззера проявился серьёзный недостаток: значения, выбранные для двух основных источников рандомизированного ввода, аргументов lParam и wParam для SendMessage и PostMessage, ограничены 16-битными целыми числами. Оба аргумента 32-битные на 32-разрядной Windows и 64-битные в 64-разрядной версии Windows. Проблема возникает в Fuzz.cpp, где устанавливаются значения lParam и wParam:

     wParam = (UINT) rand();
     lParam = (LONG) rand();

Функция rand() возвращает число в диапазоне [0, 216], что значительно ограничивает набор тестируемых значений. Мы намеренно сохранили эту ошибку во время тестирования, чтобы результаты точно сопоставлялись с оригинальной работой.

Тестируемые приложения


В оригинальном отчёте по NT тестировались 33 программы. У нас только 28, потому что для тестирования используется только одна версия каждой программы. Экосистема программного обеспечения Windows существенно изменилась с 2000 года, хотя удивительно многое осталось без изменений. Пакет Microsoft Office содержит те же программы, что в исходных тестах. Netscape Communicator превратился в Firefox. Adobe Acrobat переименовался в Adobe Reader, но по-прежнему в силе. Даже Winamp выпустил новый релиз в 2018 году, что позволяет провести справедливое сравнение с оригинальным отчётом. Тем не менее, некоторые устаревшие программы пришлось заменить. См. ниже список изменений и причины для них:

  • CD Player ? Windows Media Player: в новую программу включена функциональность CD Player.
  • Eudora ? Windows Mail: компания Qualcomm теперь занимается микросхемами, а не почтовыми клиентами. Поскольку Eudora больше не существует, вместо неё протестирован почтовый клиент Windows по умолчанию.
  • Command AntiVirus ? Avast Free Edition: Command AntiVirus больше не доступен. Его заменили на Avast как самый популярный сторонний антивирус.
  • GSView ? Photos: приложение GSView больше не поддерживается. Его заменили на программу просмотра фотографий Windows по умолчанию.
  • JavaWorkshop ? IDE NetBeans: IDE JavaWorkshop больше не поддерживается. NetBeans кажется хорошей бесплатной альтернативой, которая соответствует духу того, что нужно проверять.
  • Secure CRT ? BitVise SSH: Secure CRT всё ещё существует, но для загрузки пробной версии требуется очень длинная веб-форма. BitVise SSH предложил быструю загрузку.
  • Telnet ? Putty: приложение telnet всё ещё существует в Windows, но теперь это консольное приложение. Для фаззинга GUI мы заменили его на Putty, популярный эмулятор терминала с открытым исходным кодом для Windows.
  • Freecell и Solitaire мы нашли в наборе Microsoft Solitaire Collection из каталога приложений Windows App Store.

Конкретная версия приложения отображается в таблице результатов. Весь фаззинг проводился на 64-разрядной системе Windows 10 Pro версии 1809 (билд 17763.253).

Результаты


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

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

— из «Эмпирического исследования надёжности приложений Windows NT с использованием случайного тестирования» Джастина Форрестера и Бартона Миллера

Цифры не особенно обнадёживают, хотя ситуация улучшается. В исходном отчёте по NT все приложения вылетели или зависли на фаззинге. Теперь две программы: калькулятор и Avast Antivirus, пережили фазинг оконными сообщениями без каких-либо негативных последствий. Наша похвала командам Avast и Windows Calculator в их подходе к ошибочным оконным сообщениям. Команда Calculator заслужила дополнительный респект за открытие исходного кода и демонстрацию, как создаётся высококачественное приложение UWP. См. таблицу 1 со всеми результатами фаззинга, вместе с специфической версией используемого программного обеспечения.

Программа Версия SendMessage PostMessage
Microsoft Access 1901 сбой сбой
Adobe Reader DC 2019.010.20098 сбой ok
Calculator 10.1812.10048.0 ok ok
Windows Media Player 12.0.17763.292 сбой сбой
Visual Studio Code 1.30.2 сбой ok
Avast Free 19.2.2364 ok ok
Windows Mail 16005.11231.20182.0 сбой сбой
Excel 1901 сбой ok
Adobe FrameMaker 15.0.2.503 сбой сбой
Freecell 4.3.2112.0 сбой сбой
GhostScript 9.26 сбой ok
Photos 2019.18114.17710.0 сбой сбой
GNU Emacs 26.1 сбой сбой
IE Edge 44.17763.1.0 сбой сбой
NetBeans 10 сбой сбой
Firefox 64.0.2 сбой сбой
Notepad 1809 сбой ok
Paint 1809 сбой сбой
Paint Shop Pro 2019 21.1 сбой сбой
Powerpoint 1901 сбой ok
Bitvise SSH 8.23 сбой сбой
Solitaire 4.3.2112.0 сбой сбой
Putty 0.70 подвисание подвисание
VS Community 2017 15.9.5 сбой сбой
WinAmp 5.8 5.8 Build 3660 сбой ok
Word 1901 сбой ok
Wordpad 1809 сбой сбой
WS_FTP 12.7.0.1903 сбой сбой
Таблица 1. Результаты воспроизведения оригинального фаззинга на Windows 10. Спустя 19 лет почти все приложения по-прежнему неправильно обрабатывают искажённые оконные сообщения

Баг в Windows?


К сожалению, любопытство взяло верх, и нам пришлось сделать одно исключение. Казалось, что несколько несвязанных приложений поражает одна общая проблема. Отладка показала, что проблема связана с сообщением WM_DEVICECHANGE. Когда фаззер отправлял это сообщение, то падало даже самое простое приложение — HelloWorld, официальный пример Windows API (рис. 3).


Рис. 3. 32-битный HelloWorld.exe аварийно завершает работу при получении оконного сообщения от фаззера. Этого не должно произойти, так как программа совершенно простая. Подразумевается, что проблема где-то в Windows

После падения HelloWorld мы сразу поняли, что проблема затрагивает только 32-разрядные приложения, но не 64-разрядные. Некоторая быстрая отладка показала, что сбой происходит в wow64win.dll, слое совместимости 32-битных приложений для 64 бит. Мой поверхностный (и, возможно, неправильный) анализ проблемы позволяет сделать вывод, что функция wow64win.dll!whcbfnINDEVICECHANGE расценивает wParam как указатель на структуру DEV_BROADCAST_HANDLE64 в целевой программе. Функция преобразует эту структуру в структуру DEV_BROADCAST_HANDLE32 для совместимости с 32-битными приложениями. Сбой происходит из-за того, что значение wParam, сгенерированное фаззером, указывает на недопустимую память.

Обработка wParam как локального указателя — плохая идея, хотя, вероятно, это было преднамеренное дизайнерское решение, чтобы уведомления съёмных устройств работали с устаревшими 32-разрядными приложениями Windows. Но всё равно неправильно, что можно аварийно завершить работу другого приложения без каких-то проблем. Мы сообщили о проблеме в MSRC, хотя граница безопасности не пересекалась. Они подтвердили, что ошибка не является проблемой безопасности. Надеемся увидеть исправление этой, по общему мнению, странной проблемы в будущей версии Windows.

Вывод


Оконные сообщения недооцениваются и часто игнорируются в качестве ненадёжных входных данных для программ Windows. Даже через 19 лет после появления первого фаззера оконных сообщений с открытым исходным кодом 93% тестируемых приложений по-прежнему зависают или вылетают при запуске той же самой программы. Но обнадёживает, что некоторые приложения изящно справляются с этими искажёнными входными данными: это означает, что в некоторых организациях существуют фреймворки и институциональные знания, позволяющие избежать таких ошибок.

Конечно, фаззер можно улучшить во многих отношениях, но даже самый простой метод вызвал сбой 93% приложений. Возможно, в некоторых случаях оконные сообщения даже пересекают реальную границу безопасности. Если вы исследуете эту область, мы надеемся, что вы поделитесь находками.

Комментарии (4)


  1. artskep
    14.05.2019 18:15

    42 и 1337.
    Хм, пожалуй стоит задумываться про новый вектор атаки в виде внедрения мемов в общественное сознание, дабы скрывать уязвимости от тестеров, использующих мемы в виде сида :)
    А, кроме шуток, ведь 42 может оказаться много где. Я уж не говорю про сид 1 (сам использую, но не там, где безопасность, конечно)


  1. 0xf0a00
    14.05.2019 18:55

    О, надо будет свои проекты на Delphi погонять. :)


  1. CoolCmd
    15.05.2019 11:29
    +1

    зачем защищать куркулятор от неправильного указателя в сообщении? и как?


    1. artskep
      15.05.2019 17:42

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