Файл на 50 КБ в формате AVI, загруженный в медиатеку Jellyfin 10.11.9, запускает reverse shell от имени сервисного пользователя. Без аутентификации. Без единого клика админа. Просто файл попал в папку - и всё.
Heap out-of-bounds write в декодере MagicYUV, CVSS 8.8 HIGH, вектор
AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H. Одна ошибка в расчёте высоты chroma-плоскости - и всё, что автоматически обрабатывает медиафайлы через libavcodec, превращается в поверхность атаки. Ниже - полный разбор корневой причины, цепочки эксплуатации, поверхности атаки и практические шаги для верификации и устранения.Бизнес-логика атаки: зачем злоумышленнику PixelSmash
Прежде чем лезть в байты - зачем это атакующему. Подробнее - в нашем статье о cve эксплойт разработка.Медиасерверы (Jellyfin, Nextcloud, Emby) часто крутятся на NAS-устройствах или VPS с доступом к внутренней сети. Получив шелл от имени сервисного пользователя, атакующий получает точку опоры для латерального движения, доступ к медиатеке (а там нередко валяются корпоративные файлы и бэкапы) и возможность закрепления. Учётные данные не нужны - достаточно доставить малформированный медиафайл туда, где FFmpeg его обработает автоматически.
По MITRE ATT&CK цепочка выглядит так: Exploit Public-Facing Application (T1190, Initial Access) при загрузке на сервер, либо Exploitation for Client Execution (T1203, Execution) на десктопе, далее - Unix Shell (T1059.004, Execution) через перехваченный вызов
system().Корневая причина: рассогласование высоты слайсов в MagicYUV
MagicYUV - lossless видеокодек, не такой раскрученный как H.264 или VP9, но он скомпилирован в дефолтные upstream-сборки FFmpeg и зарегистрирован для контейнеров AVI, MKV и MOV. По данным JFrog, любое приложение, открывающее файл в этих контейнерах, может маршрутизировать поток к декодеру MagicYUV, если файл декларирует соответствующий кодек.Видеокадры в MagicYUV хранятся в формате YUV - яркостная плоскость (Y) и две цветовые (U, V). В субдискретизированных форматах типа YUV420P цветовые плоскости имеют вдвое меньшее разрешение по высоте, чем яркостная. Кадр разбивается на горизонтальные слайсы, которые декодируются независимо.
А теперь - суть бага. Аллокатор фреймов и декодер MagicYUV по-разному вычисляют высоту chroma-плоскостей при нечётном значении
slice_height, которое контролируется атакующим из битового потока:
Код:
Аллокатор: coded_height=32, chroma_height=16, буфер: строки 0..15
Декодер: slice_height=31 (из битстрима), slices=2
chroma строк/слайс = ceil(31/2) = 16
Второй слайс: start_row = 1*16 = 16 <- за пределами буфера
slice_height на фактор субдискретизации добавляет одну лишнюю chroma-строку на слайс. При двух и более слайсах эти строки накапливаются и выходят за границы выделенного буфера. Результат - запись за пределы кучи (CWE-787, Out-of-bounds Write).Патч в FFmpeg 8.1.2 добавляет проверку выравнивания
slice_height относительно вертикальной субдискретизации chroma, отклоняя некорректные значения на этапе разбора.Баг выглядит тривиально - одна пропущенная проверка границ. Но такие проверки охраняют trust-границы: любой путь, по которому недоверенный MagicYUV-поток попадает к декодеру, становится вектором атаки.
Цепочка эксплуатации: от heap overflow до вызова system()
Место в цепочке атаки
Полный kill chain:- Delivery - атакующий формирует малформированный MagicYUV-файл в контейнере AVI/MKV/MOV (~50 КБ)
- Initial Access (T1190) - файл загружается на медиасервер, попадает в папку медиатеки через торрент, или открывается через генератор миниатюр
- Execution (T1203) - FFmpeg/ffprobe автоматически декодирует файл, срабатывает OOB write
- Post-exploitation - reverse shell, загрузка инструментов (T1105, Ingress Tool Transfer), закрепление
Перехват AVBuffer.free
В FFmpeg после каждого блока пиксельных данных плоскости в куче размещается объектAVBuffer - структура управления буфером с подсчётом ссылок. Одно из её полей - указатель на функцию free(), вызываемую при освобождении буфера. Запись за границы chroma-буфера попадает на соседний AVBuffer и перезаписывает этот указатель.По данным JFrog, продемонстрированная цепочка эксплуатации работает так: NUL-терминированная shell-команда размещается по определённому OOB-смещению, указатель
AVBuffer.free перенаправляется на адрес system(), и при последующем освобождении буфера команда атакующего выполняется. Шелл срабатывает до того, как процесс FFmpeg упадёт на последующем повреждении кучи.Красиво, но есть нюансы.
Ограничения: ASLR и реальная модель угроз
Без оговорок картина будет неполной:- ASLR - главный барьер. Для надёжного RCE нужно знать адрес
system()в памяти. На системах с включённым ASLR (а это все современные дистрибутивы GNU/Linux, macOS, Windows) адресное пространство рандомизировано, и прямой перехват не пройдёт без утечки информации. JFrog подтверждает: их RCE-демонстрация проводилась с отключённым ASLR. - Потенциальная цепочка с FlashSV. Исследователи упоминают, что отдельная ошибка раскрытия информации в декодере FlashSV в FFmpeg теоретически может быть использована в цепочке с PixelSmash для обхода ASLR. Деталей и публичного PoC для этой цепочки на момент написания нет.
- DoS - надёжен всегда. Даже когда RCE невозможно, OOB write гарантированно роняет процесс FFmpeg. На серверах с автоматической обработкой это означает отказ в обслуживании медиасервиса.
- EPSS = 0.0048 (перцентиль 0.38). По данным FIRST.org, вероятность эксплуатации в течение 30 дней ниже медианы. CISA SSVC: exploitation=none, automatable=no, technical impact=total. Подтверждённых случаев эксплуатации в дикой природе на момент написания нет.
Поверхность атаки: где FFmpeg принимает недоверенный контент
FFmpeg - не просто утилита для конвертации видео. Это фреймворк из нескольких библиотек, главная из которых -libavcodec с сотнями кодеков. Приложения линкуются к ней напрямую, вызывают ffmpeg/ffprobe через shell, используют обёртки (PyAV, python-ffmpeg) или бандлят кастомные сборки. Когда уязвимый компонент - декодер внутри libavcodec, поверхность атаки следует за зависимостью.Медиасерверы
Как это выглядит на практике:- Jellyfin - монитор файловой системы обнаруживает новый файл в медиатеке и автоматически запускает сканирование метаданных через ffprobe. Эксплойт предположительно срабатывает во время сканирования - reverse shell от имени сервисного пользователя. Вектор через торрент: файл скачивается прямо в папку медиатеки, нулевое взаимодействие.
- Nextcloud - при включённом Movie preview provider загрузка видеофайла запускает генерацию миниатюры через системный FFmpeg. Достаточно, чтобы файл отобразился в списке папки.
- Emby, Immich, PhotoPrism - архитектурно уязвимы, поскольку используют FFmpeg для обработки медиа, но независимое тестирование не подтверждено публично.
NAS-устройства
Synology и QNAP поставляют FFmpeg в составе медиаиндексаторов. Генерация миниатюр при обзоре файловой системы через веб-интерфейс или мобильное приложение запускает декодирование. На ARM-архитектуре NAS-устройств ASLR-энтропия ниже, чем на x86\_64, что потенциально упрощает брутфорс адресов - но конкретных публичных исследований по этому вектору пока нет.Десктоп и облако
Генераторы миниатюр GNOME, KDE, XFCE (черезffmpegthumbnailer) срабатывают при простом открытии папки с малформированным файлом. OBS Studio, Kodi, mpv - потенциально уязвимы, поскольку используют libavcodec с включённым MagicYUV.Облачные сервисы транскодирования (AWS MediaConvert, Cloudflare Stream) потенциально уязвимы, но JFrog их не тестировал. Мессенджеры Slack, Discord, Telegram, WhatsApp используют FFmpeg для серверных превью видео - тоже не тестировались, но архитектурно вектор есть.
Практическая проверка: определяем уязвимость в инфраструктуре
Требования к окружению
- ОС: любой GNU/Linux-дистрибутив с установленным FFmpeg (Debian, Ubuntu, RHEL, Arch)
- RAM: достаточно 512 МБ для проверки, 2+ ГБ для воспроизведения в лабе с Jellyfin
- FFmpeg: уязвимы все версии до 8.1.2 (Debian зафиксировал в DSA-6361-1, пакет
ffmpeg 7:7.1.5-0+deb13u1для trixie) - Сеть: offline-проверка возможна, для теста на медиасервере нужен доступ к его интерфейсу
Шаг 1: проверить наличие декодера MagicYUV
Bash:
ffmpeg -version | head -1 # версия FFmpeg
ffmpeg -decoders 2>/dev/null | grep magicyuv
magicyuv и версия ниже 8.1.2 - система уязвима к DoS. Для RCE нужно дополнительно проверить статус ASLR: cat /proc/sys/kernel/randomize_va_space (0 = отключён, 1 = частичный, 2 = полный).Шаг 2: инвентаризация зависимостей
PixelSmash - это проблема цепочки поставок. Недостаточно проверить/usr/bin/ffmpeg. Нужно искать все бинари и библиотеки, линкующиеся к libavcodec: ldd /path/to/binary | grep avcodec для динамически слинкованных бинарей. Для каждой найденной копии - ./ffmpeg -decoders 2>/dev/null | grep magicyuv. Это единственный надёжный способ.Дополнительно:
strings /path/to/binary | grep -i magicyuv и find / -name "ffmpeg*" -executable 2>/dev/null с последующим ./ffmpeg -version для каждой найденной копии. Jellyfin, к примеру, поставляет собственный бинарь FFmpeg, который не обновляется через пакетный менеджер дистрибутива. Я на это натыкался не раз - обновляешь системный FFmpeg, а Jellyfin продолжает использовать свой древний.Шаг 3: оценка достижимости
Наличие уязвимого декодера != эксплуатируемость. Нужно ответить на вопросы: может ли недоверенный пользователь загрузить медиафайл? Запускается ли автоматическая обработка (генерация превью, сканирование метаданных, транскодирование)? Работает ли процесс FFmpeg с привилегиями, которые представляют интерес?Сканер уязвимостей типа Nessus обнаружит версию (плагин для CVE-2026-8461 основан на self-reported version), но не ответит на эти вопросы - это ручная работа пентестера.
Детектирование PixelSmash в логах
Для blue team и SOC-инженеров - что искать:- Аварийные завершения ffmpeg/ffprobe с сигналами SIGSEGV или SIGABRT сразу после обращения к файлу. Паттерн: процесс FFmpeg стартует, падает в течение секунд, в coredump виден адрес в районе heap.
- Аномальные медиафайлы. AVI/MKV/MOV размером менее 100 КБ с кодеком MagicYUV - подозрительны по определению. MagicYUV - lossless кодек для профессионального видеомонтажа. Файл в 50 КБ с этим кодеком в медиатеке домашнего сервера - красный флаг.
- Повторные краши медиасервисов. Если Jellyfin или аналогичный сервис перезапускается несколько раз подряд после добавления нового контента - возможна попытка эксплуатации (или уже успешная, если между крашами проходил вызов
system()). - Подозрительные процессы от сервисного пользователя. Reverse shell от пользователя
jellyfinилиnextcloud- прямой IoC. Мониторьте сетевые соединения от сервисных аккаунтов, которые обычно не инициируют исходящие подключения.
Чеклист устранения CVE-2026-8461
Формат для передачи сисадмину или включения в пентест-отчёт:
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
PixelSmash вскрыл проблему, которую индустрия предпочитает не замечать: FFmpeg компилируется с сотнями декодеров по умолчанию, и практически никто не собирает его с белым списком. Plex, предположительно, это сделал - и потенциально оказался защищён. Все остальные унаследовали риск молча, через зависимость, которой доверяют безоговорочно.
Одна ошибка в расчёте высоты chroma-слайса - и сотни проектов получают запись за пределы кучи в каждом пайплайне, где обрабатывается недоверенный медиаконтент.
На практике я вижу эту картину постоянно: медиаобработка воспринимается как безопасная операция. "Мы просто генерируем превью" - говорят разработчики, не задумываясь, что за этой генерацией стоит парсинг бинарного потока на C, с ручным управлением памятью, без песочницы. PixelSmash - не аномалия, а закономерный результат. Формула проста: сложный парсер + недоверенный вход + отсутствие изоляции = стабильный поток уязвимостей класса memory corruption.
Вместо того чтобы гнаться за каждым CVE, разумнее менять архитектурный подход. Медиа-парсинг нужно трактовать как десериализацию - никогда не доверять, всегда изолировать, всегда минимизировать поверхность. Собирать FFmpeg с
--disable-decoders и явным --enable-decoder= для каждого нужного формата. Запускать обработку в одноразовых контейнерах с seccomp-профилем. Это не параноидальный hardening - это базовая гигиена для любого сервиса, принимающего файлы из внешнего мира.Проверьте свой медиасервер прямо сейчас:
ffmpeg -decoders 2>/dev/null | grep magicyuv. Если строка есть, а версия ниже 8.1.2 - у вас та же проблема, что и у всех.
Последнее редактирование модератором: