Методы поиска уязвимостей в ПО без исходных кодов

Все, на что я наткнулся в ходе поисков по этой теме:

  1. Ручной поиск
  2. Поиск по шаблонам
  3. Fuzzing

Ручной поиск

О том как происходит первое двумя словами не скажешь. Исследователи опираются на свой опыт и, с каждой работой становятся еще опытнее. Полезно знать шаблонные уязвимости, уметь читать дизассемлированный код, писать код, для проверки предположений. Единственный алгоритм ручного поиска, который я встречал был описан в книге «Взлом программного обеспечения» Грега Хогланда и Гари Мак-Гроу[1].

Существуют ключевые места[1], присутствие уязвимостей в которых более вероятно, чем в остальном коде. К таким местам относится, например вызов небезопасных функций работы со строками.

Но даже если найдено подобное ключевое место, то нет гарантии, что удаться произвести на него атаку через внешние данные. Для нахождения пути, через которые вредоносные данные могут достичь уязвимого места может быть использованы методы обратной трассировки[1].

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

Далее следует несколько отдалиться от места уязвимсти ( «переместиться в другой раздел» [1 ) и попытаться внедрить уязвимые данные в исследуемом месте ( с помощью изменения содержимого памяти или регистров. Такой эксперимент покажет есть ли возможность распространить данные из текущего места к уязвимому.

У эксперимента может быть два исхода: данные удалось переместить в необходимый раздел или же нет. Так определяется проходимость раздела.

На рисунке 1 приведен пример, когда данные из одного раздела могут блокироваться фильтром, так и не достигнув уязвимого места.

Рисунок 1 – Перемещение вредоносных данных по разделам программы

Далее движение продолжается итеративно от уязвимого места к функции, принимающей пользовательский ввод, например WSARecv. Если найдена нужная цепочка разделов, то это гарантирует, что удастся организовать атаку.

Поиск по шаблонам

Поиск уязвимости по шаблону – автоматизированный метод, основанный на сравнении некоторых характеристик исследуемого ПО с заранее подготовленными описаниями (сигнатурами) уязвимых мест. Данный метод эффективен при поиске несложных уязвимостей  и немаскируемых закладок, таких как переполнение буфера, парольные константы и т.д.

Поиск уязвимостей по шаблонам проводится статически. При статическом анализе исследуется код программы без его запуска. Код программного обеспечения (в большинстве случаев исходный) сравнивается с сигнатурами из базы методом побайтового сравнения или по более сложному алгоритму. При обнаружении сходств, сообщается о найденной уязвимости. Иногда сигнатура дополняется некоторым набором эвристических правил.

Современные сканеры кода позволяют хорошо стравляются с автоматизацией шаблонного поиска следующих типов уязвимостей[2]:

—   внедрение произвольных команд;

—   SQL-инъекции;

—   XSS-запрсоы (межсайтовый скриптинг);

—   ошибоки входных и выходных значений;

—   уязвимости переполнения буфера.

Поиску шаблонов уязвимого кода посвящены множество разработок: PREfast, lint, Parasoft, Coverity, FlawFinder, ITS4, RATS а так же продукты российского производства АК-ВС, и АИСТ-С. Все они поддерживают поиск ошибок в модулях исходного кода, написанных на одном из поддерживаемых языков.

Реже статический анализ проводится по исполняемому коду. К примеру, свободно распространяемая утилита FxCop от Microsoft проводит анализ объектного кода сборок .NET. С помощью анализа кода IL анализируется соответствие разработки стандартам кодирования, принятым Microsoft (SDL).

Fuzzing

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

Часто подразумевается, что знание о тестируемом ПО получаются в ходе реверсивной инженерии[3]. На основе полученных таким путем знаний планируется и выполняется ряд мероприятий по тестированию ПО — динамический анализ.

В последнее время приобретает популярность разновидность метода тестирования «серого ящика», которое получило название фаззинг (fuzzing). Термин не так давно вошел в обиход и поэтому присутствует далеко не во всех словарях. Самое близкое значения термина «анализ граничных значений»[3] – определение доступных диапазонов входных значений программы и тестирование значений, которые выходят за этот диапазон либо находятся на границе. Фаззинг отличается тем, что не ограничивает свое внимание на граничных значениях, но так же занимается подготовкой входных данных специального вида.

Изначально фаззинг использовался для тестирования качества и отказоустойчивости ПО. В 1998 году проф. Бартон Миллер применил метод для тестирования приложений UNIX. И, несмотря на то, что поиск уязвимостей не был приоритетом тех исследований, исследования показали его пригодность в данных целях. Последний факт стал причиной популярности метода. Появились на свет множество коммерческих и свободно распространяемых продуктов для фаззинга: Protos Test Suites, PROTOS SNMP, SPIKE, Mangleme, FileFuzz, SPIKEfile, Codenomican, COMRider, AxMan.

В зависимости от метода генерации данных принято разделять подход к фаззингу на класса два:

— Мутация данных. Новые данные получаются за счет незначительных изменений существующих данных;

— Генерирование данных. Данные подготавливаются «с нуля» на основе протоколов или в соответствие с заданными правилами.

Следующие типы фаззинга, так или иначе, относятся к одному из вышеперечисленных классов:

— Использование заранее подготовленных тестовых данных. Используется для тестирования реализаций протоколов. Вместе с формальным описанием протокола разработчик может подготовить ряд тестовых данных, которые должны соответствующим образом обрабатываться программой, реализующей протокол;

— Использование случайных данных. Это наименее эффективный из возможных подходов. Целевой программе передается большое количество случайных данных. При возникновении сбоя очень сложно определить настоящую ее причину.

— Ручное изменение данных протокола. Исследователю известен протокол и он пытается добиться аномального поведения исследуемого ПО за счет внесения ошибочных данных. За счет отсутствия автоматизации мало эффективен.

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

— Осознанное внесение изменение в данные подготовленные в соответствие с протоколом. Для проведения данного вида тестирования должны быть проведены дополнительные исследования с целью определения, какие части данных должны оставаться константными, а какие изменяться. Подход является наиболее интеллектуальным, однако увеличивается затрата времени исследователя.

По типу воздействия фазеры можно разделить на несколько классов: локальные, удаленные, в памяти и универсальные.

Локальные фаззеры делятся на следующие типы:

— Фаззеры командной строки. Используются для выявления ошибок, связанных с разбором входных параметров программ;

— Фаззеры переменных окружения. Используются для выявления ошибок, связанных с обработкой данных, получаемых через переменные окружения;

— Фаззеры файлов. Используются для тестирования программного обеспечения, принимающего файлы в качестве входных данных.

Удаленные фаззеры бывают следующих типов:

— Фаззеры сетевых протоколов. В зависимости от сложности протокола применяются фазеры соответствующей сложности;

— Фазеры web-приложений. Получили особую актуальность с развитием Web 2.0.

— Фазеры web-браузеров. Тестируется правильность разбора, как HTML-тэгов, так и других поддерживаемых расширений. Особо стоит выделить фазеры com-объектов поддерживаемых браузерами.

Фаззинг в памяти напрямую воздействует на точки ввода данных в код, минуя средства доставки данных. Методика требует более детального разбора и по этой причине описана в отдельном пункте.

Под универсальными фаззерами здесь понимается инструментарий для быстрой разработки инструментов фаззинга (fuzzing framework). Такой инструментарий должен содержать в себе примитивы для генерации входных данных, а так же для их внедрения. На их основе может быть разработан фаззер необходимой конфигурации.

[1] Грег Хогланда и Гари Мак-Гроу. Взлом программного обеспечения.

[2] http://www.itsec.ru/articles2/control/audit_progr_koda_treb_bezopasn

[3] Fuzzing: исследование уязвимостей методом грубой силы. Саттон М., Грин А., Амини П.

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

Часто подразумевается, что знание о тестируемом ПО получаются в ходе реверсивной инженерии[FuzzingBruteForce]. На основе полученных таким путем знаний планируется и выполняется ряд мероприятий по тестированию ПО — динамический анализ.

В последнее время приобретает популярность разновидность метода тестирования «серого ящика», которое получило название фаззинг (fuzzing). Термин не так давно вошел в обиход и поэтому присутствует далеко не во всех словарях. Самое близкое значения термина «анализ граничных значений»[FuzzingBruteForce] – определение доступных диапазонов входных значений программы и тестирование значений, которые выходят за этот диапазон либо находятся на границе. Фаззинг отличается тем, что не ограничивает свое внимание на граничных значениях, но так же занимается подготовкой входных данных специального вида.

Изначально фаззинг использовался для тестирования качества и отказоустойчивости ПО. В 1998 году проф. Бартон Миллер применил метод для тестирования приложений UNIX. И, несмотря на то, что поиск уязвимостей не был приоритетом тех исследований, исследования показали его пригодность в данных целях. Последний факт стал причиной популярности метода. Появились на свет множество коммерческих и свободно распространяемых продуктов для фаззинга: Protos Test Suites[], PROTOS SNMP[], SPIKE[], Mangleme[], FileFuzz, SPIKEfile[], Codenomican[], COMRider, AxMan[].

В зависимости от метода генерации данных принято разделять подход к фаззингу на класса два:

Мутация данных. Новые данные получаются за счет незначительных изменений существующих данных;

Генерирование данных. Данные подготавливаются «с нуля» на основе протоколов или в соответствие с заданными правилами.

Следующие типы фаззинга, так или иначе, относятся к одному из вышеперечисленных классов:

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

Использование случайных данных. Это наименее эффективный из возможных подходов. Целевой программе передается большое количество случайных данных. При возникновении сбоя очень сложно определить настоящую ее причину.

Ручное изменение данных протокола. Исследователю известен протокол и он пытается добиться аномального поведения исследуемого ПО за счет внесения ошибочных данных. За счет отсутствия автоматизации мало эффективен.

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

Осознанное внесение изменение в данные подготовленные в соответствие с протоколом. Для проведения данного вида тестирования должны быть проведены дополнительные исследования с целью определения, какие части данных должны оставаться константными, а какие изменяться. Подход является наиболее интеллектуальным, однако увеличивается затрата времени исследователя.

По типу воздействия фазеры можно разделить на несколько классов: локальные, удаленные, в памяти и универсальные.

Локальные фаззеры делятся на следующие типы:

Фаззеры командной строки. Используются для выявления ошибок, связанных с разбором входных параметров программ;

Фаззеры переменных окружения. Используются для выявления ошибок, связанных с обработкой данных, получаемых через переменные окружения;

Фаззеры файлов. Используются для тестирования программного обеспечения, принимающего файлы в качестве входных данных.

Удаленные фаззеры бывают следующих типов:

Фаззеры сетевых протоколов. В зависимости от сложности протокола применяются фазеры соответствующей сложности;

Фазеры web-приложений. Получили особую актуальность с развитием Web 2.0.

Фазеры web-браузеров. Тестируется правильность разбора, как HTML-тэгов, так и других поддерживаемых расширений. Особо стоит выделить фазеры com-объектов поддерживаемых браузерами.

Фаззинг в памяти напрямую воздействует на точки ввода данных в код, минуя средства доставки данных. Методика требует более детального разбора и по этой причине описана в отдельном пункте.

Под универсальными фаззерами здесь понимается инструментарий для быстрой разработки инструментов фаззинга (fuzzing framework). Такой инструментарий должен содержать в себе примитивы для генерации входных данных, а так же для их внедрения. На их основе может быть разработан фаззер необходимой конфигурации.

Комментарии 17

  • о я как раз [3] читаю =) На самом деле мне кажется фаззинг наиболее многообешаюшь, тк ручной поиск так уныл =\ впрочем от опыта зависит конечно. Сейчас повнимательнее прочитаю пост =)

    • Один из авторов [3] создал утилиту, идея которой мне очень нравится — Process Stalker, а потом еще и развел ее в целый framework (PaiMai). Советую ознакомиться, если интересует автоматизированный анализ. Мне тоже автоматизация по душе. По этой причине и автоматизирую 🙂

  • прочитал, со всем согласен =) вы сподвигли меня на чтения [1], хотя после книжки по руткитам желания Хоглунда читать не было =\

    • Книга [1] была выпущена до книги о rootkit’ах. Стиль там иной. Ознакомьтесь — для общего кругозора полезно. А чем книга о rootkit’ах не понравилась?

  • слишком обзорно =\ впрочем если параллельно читать книгу по дровам нормальная база будет. Я бы не допустил читать новичка в driver development до неё.

  • А что касается whitebox fuzzing с символьным выполнением и SMT-солверами, taint анализа, предусловий (как в BitBlaze(BAP) для поиска уязвимостей после применения патчей) применения генетических алгоритмов и доугих эвристик, грамматик для повышения эффективности фаззинга? Вот такой обзор ищу. А паймей действительно уникальный в своем роде фреймворк

    • блин я тоже хочу такими словами бросатся, где набрались?

    • А вот этого всего в обзоре нет, потому что не прокачан я в этих темах. Если найдете такой обзор — поделитесь, пожалуйста. Так же буду признателен за ссылки на вышеописанные технологии. Знаком только с tain-анализом. Обзор по ним обязательно подготовлю позже.
      Генетические алгоритмы, подозреваю, для фаззинга очень пригодны. Хотел я ими поиграться. Но от генерации данных ушел в сторону анализа данных и внедрения данных. Когда-нибудь дойдет и до генерации.

      • Такого обзора похоже нет в открытых источниках, к сожалению. Может у кого-то личный есть, для себя, вот и ищу. А вообще по поиску уязвимостей как диссер пишется? Есть тут наука вообще? Тут даже ни полноту, ни точность метода выявления не оценишь в условиях, как говорится, «априорной неопределенности».

        • Пишется потихоньку 😉 Оценить можно покрытие ( выбрав свой критерий и обосновав его эффективность ). Я так же собираюсь оценивать вероятности достижения покрытия для данного источника данных. Ну и выявление уязвимостей … тут модель распространения данных предложить можно. К сожалению, конкретных примеров из диссертации сейчас представить не могу. Многое не готово. По оценке возможного покрытия статья есть. Скоро, думаю выложу ее здесь. Там есть немного «науки» 😉

        • в России можно писать диссертацию по поиску уязвимостей? Я для продолжения образования на запад хочу податся, оттуда много именно научных и исследовательких работ по этим темам, люди дипломы и phd на этом делают, так что думаю проблем с выбором научного руководителя не будет. В силу определенных причин у нас проблематично по таким направлениям в аспирантуру идти, я пробивал вопрос в своем универе, там все уныло оказалось =\

          • Меня еще в 2005 году (я тогда работал до поступления в аспирантуру) зацепило выстпления человека из сертификационной лаборатории ФСТЭК. Он говорил, что их заставляют использовать «правильные» программы, такие как АИСТ-С и EMU для анализа ПО, но по факту используюется IDA и опыт исследователей. И что нет нормального инструментария. Вот тогда и захотелось что-то подобное разработать. В университете противится не стали. Наоборот, тема интересна для всех. Мы и в CTF играем еще (ufoctf.ru). В вобщем, если за границу расхочется, то к нам идите в аспирантуру. Тут есть единомышленники 🙂

          • спасибо за приглашение, но я далековато от вас живу ^___^
            Кстате, CTF меня привлекал всегда, но не доводилось никогда участвовать. Можно какнибудь локально это организовать и поиграть самому с собой? =)

          • Можно скачать образ уже прошедших игр и поиграться с ним. Хотя конечно это игра командная и эмоций игры самому не воспроизвести.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *