Проект
Для запуска: ./script.sh
Репозиторий на гитхаб - https://github.com/LaCinquette/practice-22-23
Ход выполнения
-
Для поиска уязвимости я выбрал проект FFmpeg. Нашел в нем коммит, который соответствовал требованиям, а именно:
- Соответствовал типу CWE-476 - разыменование нулевого указателя
-
Создал докерфайл, в котором:
- Выбрал в качестве базового образа Ubuntu 22.04
- Уствновил
DEBIAN_FRONTEND=nointeractive для исключения взаимодействия с командной строкой во время установки пакетов и других команд
- Установил необходимые зависимости указанные в официальной вики
- Подготавливаю рабочее место (папка workdir)
- Скачиваю, распаковываю и перемещаю коммит с еще не исправленной уязвимостью в рабочее место
- Запускаю билд программы с помощью утилиты make
- Создаю скрипт copy_out.sh, который занимается поиском необходимого объектного файла с ошибкой и копированием его в директорию workspace/out
- Оставляю инструкцию на выполнение скрипта copy_out.sh, которая должна выполниться при запуске контейнера
-
Для автоматизации создаю скрипт script.sh, который собирает образ и запускает контейнер из которого затем забирает файл и перемещает его в текущую директорию:
- Удаляю текущую папку out (если она есть)
- Собираю образ с именем ffmpeg_image
- Запускаю контейнер на основе собранного образа, в котором передаю следующие параметры:
--rm для автоматического удаления контейнера по завершению
-v $PWD/out:/workspace/out для монтирования временной директории, через которую обЪектный файл передается на хост
- Копирую нужный файл из папки out
- Удаляю папку out
Анализ уязвимости
Источники:
- Коммит с исправленной ошибкой
- Страница на Github об уязвимости
- Письмо исследователя безопасности об уязвимости
Анализ:
Проблема:
- С помощью команды
ffmpeg -c:v dnxhd -i poc.mov -y output.ts на вход программе подается специально созданный .mov файл
- Для парсинга формата DNxHD вызывается функция dnxhd_parse в файле dnxhd_parser
- Она в свою очередь вызывает функцию dnxhd_find_frame_end (в том же файле), которая при определенных условиях не находит конец и выдает отрицательное число, не являющееся кодом ошибки
- Это число вместе с другими параметрами затем передается в функцию ff_combine_frame (находящуюся в файле parser) для соединения фреймов
- Так как это число не является кодом ошибки, то ff_combine_frame распознает это как сдвиг и пытается заново прочитать эти байты в буфере, а так как буфер в этот момент пустой, происходит разыменование нулевого указателя, что приводит к Segmentation fault
В ассемблере:
0x08000d4e - начало секции
-
movsxd rcx, dword [rbx + 0xc]
В регистре rcx получаем ссылку на pc->buffer
-
add rcx, rdi
Добавляем next к pc->buffer
-
add rcx, qword [rbx]
Добавляем pc->last_index к next и pc->buffer
-
movzx edi, byte [rcx]
Вычисляем байт по адресу rcx, но так как pc->buffer изначально null - ловим Segmentation fault
Решение:
Предотвратить обращение к невыделенному участку памяти, путем коректной обработки исключительного случая. При обнаружении отрицательного числа оставшихся байтов, продолжить обработку файла путем пропускания цикла.