[Перевод] Кража закрытых видео YouTube по одному кадру

lcbxl6zrmp-qexkbwbzf65jszyc.jpeg

В декабре 2019 года, спустя несколько месяцев после того, как я занялся хакингом по программе Google VRP, я обратил внимание на YouTube. Мне хотелось найти способ получать доступ к закрытым (Private) видео, которыми я не владею.

При загрузке видео на YouTube можно выбрать один из трёх параметров доступа. «Открытый» (Public) позволяет находить и просматривать видео любым пользователям, «Доступ по ссылке» (Unlisted) позволяет просматривать видео только пользователям, знающим ID видео (URL), «Ограниченный доступ» (Private) позволяет просматривать видео только вам или другим аккаунтам, которым дано на это разрешение.

Первым делом я загрузил видео на свой второй тестовый канал аккаунта YouTube и переключил параметры доступа видео на Private, чтобы его можно было использовать для тестирования. (Помните, что тестирование всегда нужно проводить на тех ресурсах/аккаунтах, которыми вы владеете!) Если я смогу найти способ получить доступ к видео с первого тестового аккаунта, то мы выявим наличие бага.

Я открыл YouTube под первым аккаунтом, проверил каждую функцию и нажал на каждую кнопку, которую смог найти. Каждый раз, когда я видел HTTP-запрос с указанием ID видео, я заменял его на тестовое видео с доступом Private, надеясь, что так утечёт какая-нибудь информация о нём, но успеха не добился. Похоже, что основной веб-сайт YouTube (по крайней мере, все его конечные точки, которые я протестировал) всегда проверяет, находится ли видео в состоянии Private, и когда пытается выполнить запрос к целевому закрытому видео, он всегда возвращает ошибки наподобие This video is private!.

Мне нужно найти другой способ.
В подобной ситуации отличным решением может быть проверка других продуктов/сервисов, не являющихся нашей основной целью, но каким-то образом взаимодействующих внутри с её ресурсами. Если они имеют доступ к ресурсам сайта, то есть вероятность, что у них не реализованы все уровни защиты, которые имеются у основного продукта.

Интересной целью, соответствующей этим требованиям, стал Google Ads. Это продукт, который рекламодатели используют для создания рекламы во всех сервисах Google, в том числе и на YouTube. То есть реклама, которую вы смотрите перед видео на YouTube, настраивается рекламодателями здесь, на платформе Google Ads.

Итак, я зарегистрировал аккаунт Google Ads и создал новую рекламу, которая должна воспроизводить для всех пользователей YouTube видео как рекламу с возможностью пропуска. Во время процесса создания рекламы я также повсюду пытался использовать ID целевого закрытого видео, но без малейшего успеха.

После создания рекламы я начал изучать различные функции Google Ads. Это очень масштабный продукт, и он имеет множество различных параметров и инструментов. Я пытался найти что-нибудь связанное с YouTube.

На платформе я нашёл страницу под названием Videos, где увидел список видео, используемых для моей рекламы. При нажатии на видео открывается раздел аналитики (Analytics) этого видео. В нём я нашёл встроенный проигрыватель, статистику и интересную функцию под названием Moments. Она позволяла рекламодателям «помечать» конкретные моменты видео, чтобы, видеть, когда происходят разные вещи (например, метка времени момента появления логотипа компании). Честно говоря, я не совсем понял, зачем рекламодатели используют эту функцию, однако она показалась интересной:

i0q9knzzvmf4rimpjgaked0eaac.gif

Посмотрев на логи прокси, я заметил, что каждый раз, когда я «помечал момент», передавался POST-запрос к конечной точке /GetThumbnails. Тело этого запроса содержало ID видео:
POST /aw_video/_/rpc/VideoMomentService/GetThumbnails HTTP/1.1
Host: ads.google.com
User-Agent: Internet-Explorer-6
Cookie: [удалено]

__ar={"1":"kCTeqs1F4ME","2":"12240","3":"387719230"}


Где в параметре __ar значение 1 было идентификатором видео, а значение 2 — временем момента в миллисекундах. В качестве ответа возвращалось изображение в кодировке base64, представлявшее собой миниатюру, используемую платформой Ads.

Я повторил то, что делал уже много раз: заменил в запросе ID на идентификатор закрытого видео второго аккаунта, и, к моему удивлению, получил в ответ изображение base64!

Я загуглил «base64 to image» и вставил данные base64 в первый найденный декодер. На изображении оказалась миниатюра целевого закрытого видео! Сработало! Я нашёл работающий баг IDOR (Insecure Direct Object Reference, «незащищённая прямая ссылка на объект»), благодаря которому я мог получать кадр из любого видео на YouTube с ограниченным доступом!

Но я подумал: «Хм, это всего лишь один кадр». Мы можем добиться большего.

Я хотел написать скрипт на Python с proof of concept, генерирующий настоящее движущееся «видео». Поискав информацию, я понял, что если видео записано с частотой 24 FPS, то один кадр находится на экране в течение 33 миллисекунд. То есть мне достаточно скачивать каждое изображение, начиная с 0 и выполняя инкремент на 33, а затем собрать из всех полученных кадров своего рода видео.

Я быстро написал POC, которое скачивает кадры для первых трёх секунд видео, декодирует их, а затем генерирует GIF. Чтобы протестировать код, я запустил его со своим старым видео, к которому заранее ограничил доступ, потому что мне было за него стыдно:


Итак, при помощи этого бага злоумышленник может скачать любое закрытое видео на YouTube, что, на мой взгляд, является достаточно серьёзной угрозой. Но, разумеется, она имеет некоторые ограничения, которые я не смог преодолеть:
  • В реальной ситуации вам нужно знать ID целевого видео. Их массовая утечка сама по себе будет считаться багом.
  • Так как мы получаем только изображения, доступа к звуку получить не удастся.
  • Разрешение очень низкое (но его достаточно, чтобы понять происходящее в видео).

Можно сделать вывод, что всегда стоит обращаться внимание на ситуации, когда два различных продукта имеют внутреннее взаимодействие друг с другом, так как команды разработчиков обоих продуктов лучше знают свою систему и могут упустить важные подробности при работе с ресурсами другого продукта.

Поиск подобных IDOR может быть очень монотонным и кропотливым трудом, и теперь я пытаюсь не использовать избегать простых слепых замен ID в надежде на лучшее. Если какое-то время потестировать продукт и понять его внутреннее устройство, то будет эффективнее (и интереснее) попытаться подумать о различных неожиданных действиях, о которых могли не подумать разработчики, или сделать упор на недавно реализованных функциях, или просто заняться чем-то, требующим продуманных действий. Возможно, в долговременной перспективе вам это принесёт больше удовольствия. На мой взгляд, чем больше вы понимаете систему, тем больше идей о её взломе приходит в голову естественным образом.

Но даже в самых надёжных и тщательно протестированных системах есть вероятность того, что простая замена ID в запросе позволит получить критически опасный баг.

Как развивалась ситуация


[11 декабря 2019 года] — отправлен отчёт о баге

[12 декабря 2019 года] — первоначальный триаж

[20 декабря 2019 года] — баг принят (P4 → P1)

[08 января 2020 года] — предприняты шаги по устранению бага при помощи временного отключения функции Moments

[17 января 2020 года] — выписана награда в размере 5000 долларов

[??? ? 2020 года] — функция Moments снова включена, теперь она проверяет наличие доступа к видео.


На правах рекламы


VDSina предлагает VDS с посуточной оплатой, возможностью в пару кликов создать собственную конфигурацию сервера, установить любую операционную систему. Каждый сервер подключён к интернет-каналу в 500 Мегабит и бесплатно защищён от DDoS-атак!

Подписывайтесь на наш чат в Telegram.

8p3vz47nluspfyc0axlkx88gdua.png

© Habrahabr.ru