Адаптируем фаззинг для поиска уязвимостей |
||
МЕНЮ Главная страница Поиск Регистрация на сайте Помощь проекту Архив новостей ТЕМЫ Новости ИИ Голосовой помощник Разработка ИИГородские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Искусственный интеллект Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Нейронные сети начинающим Психология ИИ Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Творчество ИИ Техническое зрение Чат-боты Авторизация |
2024-09-23 11:19 Фаззинг — очень популярная методика тестирования программного обеспечения случайными входными данными. В сети огромное количество материалов о том, как находить дефекты ПО его помощью. При этом в публичном пространстве почти нет статей и выступлений о том, как искать уязвимости с помощью фаззинга. Возможно, исследователи безопасности не хотят делиться своими секретами. Тем интереснее рассмотреть эту тему в данной статье. Я занимаюсь исследованиями безопасности операционных систем и фаззингом несколько лет. Мне нравится этот инструмент, поскольку он позволяет делегировать компьютеру утомительную задачу написания тестов для ПО. При этом способы использования фаззинга могут сильно различаться в зависимости от целей его применения. В частности, разработчик использует фаззер для своего кода, чтобы найти все имеющиеся в нем ошибки. Поэтому обычно разработчик включает в своем проекте все доступные детекторы ошибок и разбирает все случаи их срабатывания, которые обнаруживаются при фаззинге. У исследователя безопасности иные цели:
В данной статье я расскажу, как перечисленные особенности влияют на настройку и использование фаззера. Для того чтобы статья была конкретной, я рассмотрю свой любимый ядерный фаззер syzkaller. Это известный открытый проект, он используется для динамического анализа ядра во многих операционных системах. Я уже несколько лет использую его для исследования безопасности ядра Linux. Архитектура фаззера syzkaller На схеме представлена архитектура syzkaller — см. рис. 1. Главная часть и основная логика фаззера syzkaller находится в компоненте syz-manager. Он отвечает за управление виртуальными машинами в процессе фаззинга. Также syz-manager работает с набором программ для тестирования ядра, который называется корпус. Он добавляет в корпус новые перспективные программы и удаляет бесполезные. Эти программы по сути являются случайными входными данными для фаззинга ядра. Они написаны на специальном языке syzlang, который задает формат и аргументы системных вызовов Linux. Если в процессе фаззинга ядро уходит в отказ (возникает kernel crash), то фаззер сохраняет это событие в базу и пытается сгенерировать минимальный репродюсер — самую короткую комбинацию системных вызовов, которая способна вызвать эту ошибку в ядре. Сам процесс фаззинга ядра происходит внутри виртуальной машины. В ее пользовательском пространстве работают части syzkaller, исполняющие системные вызовы и собирающие метрики покрытия кода ядра по итогу тестирования. Эта информация передается в syz-manager, который использует ее при выборе перспективных программ для фаззинг-корпуса. Это очень эффективная технология, которая называется обратной связью по покрытию (coverage guided fuzzing). Также при фаззинге Linux очень важны детекторы ошибок в ядре и так называемые санитайзеры. Они нужны для того, чтобы увести ядро в отказ при возникновении нештатной ситуации. Без них возникшая ошибка, например использование памяти после освобождения, не будет обнаружена и фаззинг, по сути, будет бесполезен. Такова базовая архитектура фаззера syzkaller. А теперь рассмотрим, как адаптировать его для поиска уязвимостей в ядре Linux. Как искать уязвимости в ядре Linux с помощью фаззинга Уязвимости в ядре Linux можно разделить на два класса:
Для того чтобы syzkaller находил исключительно ошибки, потенциально приводящие к LPE, нужна единственная модификация — запуск фаззера внутри виртуальной машины без привилегий администратора. В этом случае системные вызовы будут исполняться под учетной записью непривилегированного пользователя и тестироваться будет только поверхность атаки ядра Linux, что отражено на схеме (см. рис. 2). Для поиска ошибок, потенциально приводящих к RCE, требуется другой подход: нужен фаззинг сетевых интерфейсов ядра Linux. Это детально описано в отличной статье Андрея Коновалова Looking for Remote Code Execution bugs in the Linux kernel. В ней он показал устройство виртуального сетевого интерфейса TUN/TAP и специального вызова syz_emit_ethernet, которые позволяют фаззеру syzkaller взаимодействовать с сетевым стеком ядра Linux. Как находить стабильно проявляющиеся уязвимости Как было сказано выше, для исследователя безопасности большую ценность представляют ошибки, которые можно сравнительно быстро и надежно спровоцировать в системе. В syz-manager заложена определенная логика, которая срабатывает при обнаружении отказа ядра. Он начинает тестировать весь большой комплект системных вызовов, который спровоцировал ошибку, и методом дихотомии постепенно находит минимальную программу-репродюсер, которая приводит к искомому эффекту. Этот процесс работает нестабильно из-за различных побочных эффектов и состояний гонки в ядре. Поэтому при поиске репродюсера часто бывают ошибки 1-го и 2-го рода. Чтобы исследователь безопасности не тратил время и силы на разбор нестабильных репродюсеров, ему стоит спроектировать автоматическую систему сортировки результатов фаззинга (отражено на схеме — см. рис. 4). Я тоже разработал такую автоматизацию под свои критерии поиска. Это легко сделать с помощью утилиты syz-repro, которая позволяет несколько раз повторять процесс выявления минимального репродюсера. Как находить уникальные уязвимости Перейдем к наиболее интересной части статьи и рассмотрим, как находить уникальные уязвимости, которые с невысокой вероятностью найдут другие исследователи. На представленной схеме (см. рис. 5) я отметил красным цветом и пронумеровал компоненты фаззера syzkaller и ядра Linux, которые должны быть модифицированы для того, чтобы получать уникальные находки.
Заключение Поделившись этими идеями, в заключение расскажу короткую историю. В 2021 году я нашел в ядре Linux уязвимость CVE-2021-26708. При исследовании методов ее эксплуатации мне нужен был особый heap-spraying-примитив — ядерный объект, размер и содержимое которого может контролировать атакующий из пользовательского пространства. Ни один из публично известных эксплойт-примитивов не подходил. После долгого изнурительного чтения исходного кода ядра я решил делегировать эту задачу компьютеру и использовать фаззинг для поиска нужного объекта. Так я изобрел heap spraying с помощью ядерного объекта msg_msg, который затем стал очень популярным в исследовательском сообществе. Поэтому фаззинг — это замечательный инструмент, который может быть полезен исследователю безопасности не только для поиска уязвимостей. При этом фаззинг требует от исследователя готовности рискнуть своим временем и вычислительными мощностями своих серверов. Источник: ptresearch.media Комментарии: |
|