Эта статья — опыт использования фаззинга для поиска уязвимостей в современных браузерах. Авторы знают, о чем говорят: на прошедшей недавно конференции PHD они выиграли конкурс «Взломай и унеси». Взломали они Safari (продемонстрировав рабочий 0day для версии под Windows), а домой унесли призовой ноутбук.

 

Введение в профессию

Итак, приступим? Зафиксируем для порядка список существующих браузеров:

  • Windows Internet Explorer (6/7/8)
  • Mozilla Firefox (3*/4*)
  • Google Chrome
  • Safari
  • Opera
  • Opera Mini
  • Netscape Navigator
  • Midori
  • Skyfire
  • Dolphin
  • Konpueror
  • Dooble

Из них только три продукта являются OpenSource-проектами: это Chrome, Firefox и Konqueror. Все браузеры спроектированы на основе некоторого базового функционала (engine-движка). Вот перечень существующих движков:

  • Amaya
  • Gecko
  • HTMLayout
  • KHTML
  • Presto
  • Prince
  • Trident
  • WebKit

Например, Chrome и Safari построены на OpenSource-движке WebKit, а популярный Firefox — на Gecko. Для работы JavaScript используют движки данного интерпретатора, вот, например, в Google используется V8 (хотя есть еще Rhino и SpiderMonkey). Также большинство браузеров поддерживают разные плагины, такие как flash, jre (для работы с апплетами) — это дополнительные векторы атак.

 

Фаззер для браузера

Как и во многих других ситуациях, одним из самых эффективных способов поиска уязвимостей в браузере является фаззинг. Публичных и действительно работающих инструментов здесь не так много, но одним из таковых является замечательная разработка cross_fuzz от Михаила Залевски. Миша работает в Google и с помощью своего фаззера обнаружил более ста багов во всех популярных веб-браузерах, многие из них оказались эксплуатируемы. В его блоге (bit.ly/lbgfqm) есть даже отчет о найденных уязвимостях для Internet Explorer, Firefox, Opera, а также браузеров на движке WebKit. Некоторые из найденных ошибок (даже несмотря на то, что разработчики поставлены в известность) до сих пор не устранены!
При всей своей эффективности cross_fuzz устроен довольно просто.

Фаззер выявляет проблемы путем создания чрезвычайно длинных закрученных последовательностей DOM-операций, которые затрагивают сразу несколько документов. Проверяя возвращаемые объекты и вновь рекурсивно используя их, удается создавать круговые зависимости узлов, с помощью которых устраивается настоящий стресс-тест для механизмов сборки мусора браузера. Таким образом, проверяется способность приложения к правильному и эффективному освобождению памяти для более неиспользуемых объектов. Как показывает практика, выдержать удар браузеру удается далеко не всегда :). Код cross_fuzz написан на HTML/ JavaScript (lcamtuf.coredump.cx/cross_fuzz), поэтому для фаззинга достаточно открыть нужный HTML-файл (есть разные варианты с незначительными отличиями) в браузере. Чтобы нивелировать сетевые задержки, лучше всего скачать исходник на локальную машину. Не забудь при этом выкачать все зависимости (папку /targets и файлы mersenne.js/logo.jpg). Для корректной работы также потребуется включить popup’ы в браузере.

 

Начинаем практиковаться

В качестве подопытных кроликов мы взяли наиболее распространенные браузеры:

  • Firefox 3.6.16;
  • Firefox 4.0.1;
  • Chrome 10;
  • Internet Explorer 8/9;
  • Safari 5.0.5.

Открываем HTML-страницу фаззера в каждом из них — и первые результаты не заставляют себя ждать.
Удивительно, но при запуске cross_fuzz в Safari, падение было моментальным — менее чем через 5 секунд. При тестировании Firefox 3.6.16 были падения через 15-30 минут после запуска.

В основном это были падения по DEP. Это своеобразный маркер уязвимостей use-after-free, креши на исполнении потенциально эксплуатабельны и поэтому ценны. Если поменять некоторые условия при запуске, можно уменьшить время срабатывания до 3-5 минут. При тестировании Chrome падения были в дочернем процессе. IE же, что опять же удивительно, ничем не отличился.

Все эти факты меня сильно удивили: я только начал исследовать браузеры, причем делал это публичным фаззером, а уже есть креши. Черт подери, сколько же там багов, если так быстро можно уронить почти любой браузер? Учитывая такие бодрые и быстрые результаты, я про себя отметил, что правильно выбрал вектор атаки.

Cross_fuzz отлично ищет уязвимости в работе с DOM, и этим глупо не воспользоваться.

 

Включаем логирование и воспроизводим креши

Алгоритм работы фаззера подразумевает генерацию огромного количества обращений к DOM. Фаззеру приходится перебирать множество вариантов, прежде чем браузер вылетит с ошибкой. Но нам мало просто крешнуть приложение — обязательно нужно понять, почему это произошло. Чтобы разобраться, какая последовательность вызовов вызывает креш, нужно включить режим логирования.

Самый простой способ сделать это — чуть подредактировать исходники cross_fuzz и убрать return из функции LOG(message). Убрав немедленный выход из функции логирования, мы добьемся того, что на странице cross_fuzz будут отображаться все вызываемые функции.

К сожалению, cross_fuzz не умеет записывать эти данные в файл. Но для этих целей можно использовать плагины, например, Firebug для Firefox. Для логирования чего-либо в JS нужно вставить следующий код:

try {
console.log('eval %s',name);
ret_value = eval('target.' + name + '(' + par_str + ')');
} catch (e) {

Я немного пропатчил Firebug, чтобы тот мог писать свой лог в файл (исправленный вариант ищи на нашем диске). В результате все действия фаззера (в том числе те, которые приводят к крешу) пишутся в лог в C:\Documents and Settings\username\Application Data\Mozilla\Firefox\ Profiles\XXXXXX.default\js. Тот же самый трюк можно провернуть и в других браузерах, воспользовавшись соответствующими аддонами:

  • для Chrome: Firebug Lite for Google Chrome (есть еще встроенный в Chrome);
  • для Opera: Opera Dragonfly;
  • для Safari: WebKitDeveloperExtras.

После этого мы можем изучить все, что происходило в cross_fuzz, а, значит, и попытаться воспроизвести креши.

 

Как анализировать креши?

Уронить программу (пусть даже понимая, как) мало. Нам необходимо проанализировать креши и определить, эксплуатируемые они или нет.

Эта тема настолько многогранна, что она явно выходит за рамки этого материала. Наша задача на сегодня — определить ошибки в программе, которые теоретически можно эксплуатировать. А о том, как пишутся сплоиты, обходятся песочницы и защитные механизмы вроде DEP/ ASLR в журнале было немало статей (хотя одних только материалов журнала ][ тут, по правде говоря, недостаточно). Могу лишь дать пару полезных советов. Когда разбираешь креши в таких немаленьких программах как браузеры, немало нервов и времени спасают так называемые отладочные символы. Эта информация позволяет человеку использовать «символические» (отладочные) данные о двоичном файле, такие как имена переменных, процедур и функция из исходного кода. Эта информация может быть крайне полезной во время поиска ошибок в исходном коде, отладке программы и разного рода отказах.

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

При проверке отладочных символов для Safari (bit.ly/jiHbQA) выяснилось, что для ключевых модулей (Webkit.dll, JavaScriptCore.dll) отладочная информация на сервере отсутствует. Поэтому, чтобы получить ее, придется собирать WebKit самому. Исходники всегда доступны здесь — svn.webkit.org/repository/webkit, а инструкция для сборки здесь — trac.webkit.org/wiki/BuildingOnWindows. Еще один совет касается отладки Chrome. По умолчанию этот браузер создает для каждой вкладки отдельный процесс, что для нас не подходит.

Поэтому его лучше запускать с ключом «--single-process»: в этом режиме все вкладки будут запущены в единственном процессе. Что касается анализа крешей в Safari, для которого мы и написали 0dayсплоит, то тут есть еще один нюанс — подробнее о нем ты можешь прочитать во врезке.

 

Результаты фаззинга

Что получилось в результате нашего исследования?

 

Firefox третьей ветки:

Есть креши, но их не получилось воспроизвести, даже зная весь лог во время падения. Уязвимость сильно связана с состоянием динамической памяти (heap).

 

Firefox, ветка четыре:

Крешей не было зафиксировано.

 

Chrome:

Есть креши, но их не получилось воспроизвести — такая же история, как и с Firefox третьей ветки.

 

Safari:

Креши были, воспроизвести можно. Сплоит написан :). Браузеры — это очень сложное ПО. Поэтому нет ничего удивительного, что в них есть уязвимости. Всем известно: безопасность обратно пропорциональна объему и сложности кода. У браузера очень много векторов атаки: чего стоит один только SVG, про который в этой статье не упоминалось. Большая часть крешей, вызванных фаззером, не являются гарантией успеха и завязаны на большом числе факторов состояния кучи и многих других параметров. Из этого можно сделать вывод, что для реализации на 100% надежного сплоита нужно потратить очень много сил, времени и нервов. Тем не менее, используя данную методику, вполне можно найти уязвимости в браузере, что мы доказали, обнаружив уязвимость нулевого дня в Safari на Positive Hack Days.

 

Особенности анализа крешей Safari

Важный момент. Если Safari падает с исключением типа «User mode write access violations that are not near NULL are exploitable», нужно посмотреть дизасм по eip.

and dword ptr ds:0BBADBEEFh, 0
xor eax, eax
call eax

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

 

Links

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии