Содержание статьи
Что мы знаем
Этот вектор атак возможен из-за уязвимостей, обнаруженных в популярных стриминговых платформах, включая VLC, Kodi (XBMC), Popcorn Time и strem.io. Перед злоумышленником он открывает безграничные возможности: кражу конфиденциальной информации, установку программ-вымогателей, массовые DDoS-атаки и многое другое.
К счастью, эти уязвимости были устранены очень быстро после публикации первых материалов, поэтому теперь мы можем рассказать о проблеме во всех подробностях.
Popcorn Time
Созданная всего за несколько недель как проект open source мультиплатформа «Netflix для пиратов» оказалась гремучей смесью из BitTorrent-клиента, медиаплеера и бесконечных возможностей скрейпинга (сбора данных при помощи скриптов), объединенных очень привлекательным графическим интерфейсом.
![Popcorn Time GUI](https://xakep.ru/wp-content/uploads/2017/08/134724/figure-1.jpg)
Хотя программа стала очень популярна благодаря простоте использования и хорошей коллекции видеофильмов, разработчики неожиданно закрыли проект из-за давления со стороны Американской ассоциации кинокомпаний (MPAA).
После этого разные инициативные группы создали форки Popcorn Time для поддержки программы и разработки новых функций. Создатели оригинального Popcorn Time поддержали версию popcorntime.io (позднее — popcorntime.sh) как преемника своего закрытого проекта.
Интерфейс на основе WebKit содержит гору информации о фильмах и метаданные. Здесь есть трейлеры, краткое содержание сюжета, информация об актерах, фотографии обложек, рейтинги IMDb и многое другое.
Субтитры в Popcorn Time
Чтобы еще больше облегчить жизнь пользователя, субтитры к фильмам подгружаются автоматически. Можно ли использовать это в своих целях? (Подсказка: да.)
Без ведома пользователя Popcorn Time получает субтитры с единственного поставщика — OpenSubtitles. Более четырех миллионов субтитров и очень удобный API делают этот репозиторий суперпопулярным. В нем есть алгоритм выдачи рекомендаций, помогающий пользователю выбрать файл для конкретного фильма и релиза.
Поверхность атаки
Как упоминалось, Popcorn Time работает на движке WebKit, а именно NW.js. Ранее известная как node-webkit, платформа NW.js позволяет разработчику использовать веб-технологии — например, HTML5, CSS3 и WebGL — в своих родных приложениях. Более того, обращаться к API Node.js и модулям третьих сторон можно напрямую из DOM.
В сущности, приложение NW.js — это веб-страница с произвольным содержимым, написанная на JavaScript или HTML и оформленная с помощью CSS. Как всякая веб-страница, приложение может подвергаться XSS-атакам. В данном случае из-за того, что программа работает на Node.js, XSS позволяет использовать возможности серверной части. Иными словами, запросы XSS в реальности становятся запросами RCE (на выполнение удаленного кода).
На старт, внимание, марш!
Наше приключение начинается, как только пользователь включает воспроизведение фильма. Popcorn Time делает запрос через упомянутый API и скачивает рекомендованные субтитры (мы опишем этот процесс в деталях ниже). Затем Popcorn Time пытается перекодировать полученный файл в формат SRT.
![/src/app/vendor/videojshooks.js](https://xakep.ru/wp-content/uploads/2017/08/134724/Figure-2.png)
После перекодировок и парсинга созданный элемент (субтитр) прикрепляется к экрану в нужный момент, опираясь на массив «подсказок».
![Функция updateDisplay](https://xakep.ru/wp-content/uploads/2017/08/134724/Figure-3.jpg)
Это дает нам возможность добавить к отображаемому виду любой HTML-объект. Очевидно, что полный контроль над каким-либо HTML-элементом — это уже опасно. Однако, когда мы имеем дело с приложениями на основе узлов (node-based), важно понимать, что XSS равен RCE. Системные команды легко запускаются через модули типа child_process. Как только наш непроверенный JavaScript загружается на экран, до запуска вредоносного кода остается всего лишь несколько строк.
Обычный SRT-файл выглядит примерно так:
1
00:00:01,000 –> 00:00:05,000
Hello World
Вместо текста Hello World мы можем использовать HTML-тег изображения.
Мы пытаемся загрузить несуществующее изображение с атрибутом событий onerror, который позволяет задать срабатывание скрипта при возникновении ошибки во время загрузки внешнего файла.
![malicious.srt — пример](https://xakep.ru/wp-content/uploads/2017/08/134724/Figure-4.jpg)
Мы используем функцию JavaScript, связанную с атрибутом onerror
, чтобы удалить компрометирующий нас значок отсутствующего изображения и прикрепить к странице нашу вредоносную удаленную полезную нагрузку (payload). Само собой, наш скрипт evil.js всего лишь запустит окно стандартного калькулятора calc.exe.
![evil.js (Command execution)](https://xakep.ru/wp-content/uploads/2017/08/134724/Figure-5.jpg)
OpenSubtitles
Итак, мы можем исполнять код на Popcorn Time. Уязвимости на стороне клиента ценны, но их эксплуатация, как правило, требует какого-либо взаимодействия пользователя с системой — он должен кликнуть на ссылку, прочитать PDF-файл или зайти на взломанный сайт. В случае с субтитрами пользователь должен загрузить вредоносный файл. Можно ли как-то пропустить этот шаг?
Мы знаем, что юзеры беспечно скачивают субтитры из открытых источников в интернете и считают их безобидными текстовыми файлами. Более четырех миллионов файлов и около пяти миллионов ежедневных скачиваний делают OpenSubtitles крупнейшим онлайн-хранилищем субтитров. Их многофункциональный API также часто интегрируется во многие другие видеоплееры. Они даже предлагают возможность «умного» поиска: эта цепная функция выбирает наиболее подходящие субтитры по введенной информации.
Возникает вопрос: можно ли вмешаться в этот API и сделать так, чтобы взаимодействовать с пользователем не было необходимости и из базы OpenSubtitles автоматически загружались именно вредоносные субтитры?
Как работает API
Когда пользователь запускает воспроизведение фильма, система автоматически отправляет запрос на поиск субтитров SearchSubtitles — XML, содержащий все объекты субтитра, соответствующие нашим критериям (IMDb ID).
Здесь параметр поиска обозначен как imdbid
. Ответ на запрос содержит все субтитры с данным imdbid
.
А теперь самое интересное. В API имеется алгоритм, который ранжирует субтитры по их названию, IMDb ID, рейтингу загрузчика и другим параметрам. Просмотрев документацию, мы обнаружили схему такого ранжирования.
![Документация метода ранжирования API](https://xakep.ru/wp-content/uploads/2017/08/134724/Figure-8.jpg)
Здесь видно, сколько баллов добавляется к рейтингу субтитров на основе их соответствия следующим критериям: метка, IMDb ID, пользователь-загрузчик и так далее. Предположим, что мы как анонимные пользователи (user | anon) загрузили наши вредоносные субтитры в базу OpenSubtitles — нашему файлу присвоят всего пять баллов. Вот что мы узнали: недостаточно только читать документацию, поскольку исходный код проявляется в недокументированном поведении.
![Алгоритм ранжирования OpenSubtitles API](https://xakep.ru/wp-content/uploads/2017/08/134724/Figure-9.jpg)
Запрос, отправленный Popcorn Time, задает только один параметр — IMDb ID, это означает, что условие MatchedBy === 'tag'
(«метка») всегда будет иметь логическое значение «ложь». Это вызовет функцию matchTags()
.
![Функция matchTags](https://xakep.ru/wp-content/uploads/2017/08/134724/Figure-10.jpg)
Функция matchTags разбивает название фильма и субтитров на отдельные метки. Метка (тег) — это, как правило, отдельное слово или цифра, обнаруженное в названии файла. Они обычно разделяются точками (.) и дефисами (-). Число общих меток в названии файла с фильмом и названии файла субтитров затем делится на число меток фильма и умножается на показатель maxScore, равный семи. Такое значение maxScore присваивается в случае полного соответствия между двумя именами файлов. Например, если название файла с фильмом Trolls.2016.BDRip.x264-[YTS.AG].mp4, у него будут следующие метки:
[Trolls, 2016, BDRip, x264, YTS, AG, mp4]
Поскольку название файла с фильмом, который скачивается приложением (например, Popcorn Time), узнать достаточно легко (c помощью сниффера), мы можем присвоить нашему файлу с субтитрами точно такое же название, но с расширением srt. Это увеличит рейтинг файла субтитров на целых семь (!) баллов.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»