Как мы обнаружили потенциальные атаки при помощи штрих-кодов |
||
МЕНЮ Главная страница Поиск Регистрация на сайте Помощь проекту Архив новостей ТЕМЫ Новости ИИ Голосовой помощник Разработка ИИГородские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Искусственный интеллект Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Нейронные сети начинающим Психология ИИ Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Творчество ИИ Техническое зрение Чат-боты Авторизация |
2024-11-14 12:08 Фаззинг — одна из самых успешных методик для поиска багов безопасности, о нём постоянно говорят в статьях и на отраслевых конференциях. Он стал настолько популярным, что большинство важного ПО, казалось бы, должно подвергаться тщательному фаззингу. Но это не всегда так. В этом посте мы покажем, как фаззили библиотеку сканирования штрих-кодов ZBar, и почему, несмотря на ограниченность по времени, обнаружили в ней серьёзные баги: запись в буфер стека out-of-bounds, которая может привести к произвольному выполнению кода при помощи зловредного штрих-кода, и утечку памяти, которую можно использовать для выполнения атаки «отказ в обслуживании» (denial-of-service). Оценка состояния фаззинга проекта Вы можете задать вопрос: как мы узнали, что ПО не подвергалось фаззингу? Хотя чёткого ответа на него нет, можно сделать обоснованные предположения. Во-первых, можно проверить наличие упоминания фаззинга в репозитории, в том числе поискать по issue, пул-реквестам и в самом коде. Например, в этом issue предлагается обвязка для фаззинга, но, похоже, её так никогда и не запускали. Во-вторых, можно проверить проекты oss-fuzz. Если проект подвергался фаззингу при помощи oss-fuzz, то стоит проверить, нацелена ли была обвязка фаззинга на интересующую нас функциональность и работает ли проект вообще. Мы видели случаи, в которых сборки проектов завершались неудачами в течение нескольких месяцев и не подвергались активному фаззингу. Кроме репозитория проекта, интересная информация может содержаться в issue oss-fuzz и в пул-реквестах. Разработчики выразили некоторый интерес к проверке ZBar при помощи oss-fuzz, но в конечном итоге отказались от этой идеи. На этом этапе мы знали о ZBar две вещи: то, что её едва проверяли фаззингом (или вообще не проверяли), а также возможные начальные точки для создания собственной кампании по фаззингу. Оснащаем сборку Для фаззинга ZBar её нужно собрать с инструментацией санитайзера и фаззера. Сборка незнакомого проекта сама по себе может быть длительным занятием, а добавление инструментации для фаззинга часто делает эту задачу ещё более сложной. Поэтому полезно будет взять готовую сборку и модифицировать её. К счастью, ZBar уже упакована в Nixpkgs, так что мы можем быстро изменить сборку:
Пакеты Nix описываются на языке программирования Nix, и ими можно легко манипулировать различным образом. В приведённом выше случае мы использовали переопределение, чтобы модифицировать определённые пакетом входные данные, заменив компилятор на Clang (в противном случае по умолчанию используется GCC). Последующая функция overrideAttrs — это произвольное переопределение, позволяющее нам изменить всё необходимое. При помощи overrideAttrs мы добавляем недостающую зависимость openmp , отключаем stripping, чтобы правильно работали отладочные сборки, и отключаем тесты. Далее мы добавляем флаги инструментации компилятора и компоновщика для AddressSanitizer и libFuzzer. (Если вы незнакомы с флагами инструментации, то в нашей AppSec Testing Handbook есть замечательное руководство по ним.) Очевидно, Nix — не единственное решение этой проблемы. В некоторых случаях, зависящих от ПО и способов создания пакетов, настройка существующих пакетов может быть сложнее. Однако мы крайне рекомендуем попробовать его, потому что для нас он часто оказывался самым быстрым способом достижения целей. Как выявить цель для фаззинга Подготовив инструментацию, мы должны выявить цель для фаззинга. Это сильно зависит от проекта и может быть нетривиальной задачей. К счастью, в ZBar цель достаточно очевидна: функция, получающая изображение и декодирующая из него данные. На этом этапе нам нужно ответить на несколько вопросов. Насколько большим должно быть изображение? По умолчанию ZBar пытается считывать все известные типы кодов. Нужно ли нам сконфигурировать сканер на конкретные коды или просто пробовать их все одновременно? Мы считаем, что здесь не нужно слишком углубляться и просто попробовать что-нибудь, чтобы проверить, как ведёт себя библиотека. Мы начали со следующей обвязки, созданной на основе официального примера:
В этой обвязке мы, по сути, изменили пример так, чтобы входное изображение бралось из фаззера, и ограничили его квадратом 2 на 2 пикселя (8 бита на пиксель). Запуск этой обвязки привёл к одному вылету LeakSanitizer с сообщением об утечке памяти. Так как libFuzzer останавливается на первом вылете, мы отключили распознавание утечек памяти при помощи -detect_leaks=0 и продолжили фаззинг. Спустя какое-то время рост покрытия прекратился, поэтому мы решили увеличить входное изображение до размера 4x4. К нашему удивлению, у libFuzzer возникли сложности с определением того, что входные данные должны иметь размер 1024, и он не мог начать фаззинг. Не помогло даже изменение max_len и len_control . Мы смогли запустить фаззинг вручную, передав порождающие входные данные нужного размера:
После этого фаззер смог быстро найти другой вылет AddressSanitizer, вызванный переполнением буфера стека. Если вы обратили внимание на код инструментации ZBar, то заметили комментарий, что тесты отключены из-за сбоя санитайзера. Оказалось, что сбой во время тестов не был ложноположительным и касался того же бага, что и обнаруженный фаззером. Даже при такой простой методике мы смогли найти в библиотеке несколько багов. Однако, если бы у нас было больше времени, мы бы могли внести множество улучшений, чтобы найти ещё больше багов:
Диагностируем вылеты Оказалось, что о баге записи в буфер стека out-of-bounds независимо от нас сообщил ещё один исследователь. Уязвимости был присвоен CVE-2023-40890, и её устранили в коммите 012a030. Как указал фаззер, проблема скрывалась в функции
Баг утечки памяти открывал вектор denial-of-service, в частности, потому, что размер утечки зависел от входных данных; похоже, что он равен размеру границы изображения / 2 * 8 * 3 байта , так что для изображения с границей в 512 утечка составляет 6 КиБ. Программа, многократно использующая ZBar для сканирования ненадёжных кодов, в конечном итоге исчерпает память и вылетит. Первопричина находилась в функции _zbar_sq_decode , которой при определённых условиях ошибки не удаётся освободить выделенную память. На это тоже правильно указал фаззер:
Первопричиной утечки стало отсутствие очистки памяти на путях возникновения ошибки. В двух случаях функция _zbar_sq_decode выполняла возврат без выполнения кода очистки под меткой free_borders .
Мы сообщили об этой проблеме мейнтейнеру и выслали патч, однако долгое время не получали никакой реакции. Мы опубликовали этот патч в своём форке ZBar и открыли пул-реквест в upstream-репозиторий ZBar. Объединяем всё вместе Чтобы воспроизвести описанное в посте исследование, сохраните показанную выше обвязку фаззинга как Выводы Из этого эксперимента можно сделать несколько выводов. Во-первых, важно проводить фаззинг небезопасного кода, даже если у вас особо нет на это времени. Другие исследователи могут продолжить вашу работу, расширив покрытие кода фаззером.
Или при использовании CLI-программы zbarimg можно добавить опции --set '*.enable=0' --set 'qr.enable=1' .Наконец, добавьте в свою сборку инструментацию санитайзеров. Как минимум следует использовать AddressSanitizer. Как видно из этого примера с ZBar, если бы тесты собирались с санитайзерами, то они бы обнаружили критическую уязвимость безопасности памяти. Ещё одно преимущество заключается в том, что санитайзеры экономят время и усилия по добавлению фаззинга в проект, поскольку санитайзеры — это, по сути, обязательный этап для фаззинга кода на C/C++. Источник: habr.com Комментарии: |
|