Занимаясь исследованиями безопасности, я часто сталкиваюсь со странными причудами и поведением, которые могут пригодиться, разве что, в качестве весёлого фокуса на вечеринке. Тем не менее мне нравится их отслеживать. Кто знает, возможно, однажды что-то из этого окажется как раз тем самым недостающим элементом.

▍ Часть 1: видео с кошками


Кто не любит видео с кошками?

На Google Slides есть прикольная возможность добавлять YouTube-ролики в свои презентации. Нужно просто открыть окно выбора видео, найти нужный клип и добавить его в слайд.
В результате отобразится iframe, ссылающийся на www.youtube.com/embed/{VIDEOID}, внутри которого воспроизводится ваше видео с милыми котиками. Неплохо! Но можем ли мы сделать что-то, помимо простого воспроизведения видео?



С позиции сетевого трафика всё выглядит так, будто добавление видео в слайд приведёт к отправке на Slides videoid, который затем используется для построения встраиваемого URL для iframe. Мы не можем контролировать весь URL, только его часть videoid. Но можем ли мы всё равно что-то сделать?

Очевидным решением здесь будет попытка применить обход пути. Если мы изменим videoid на ../, то весь URL будет выглядеть как www.youtube.com/embed/.., который должен превратиться просто в www.youtube.com, ведущий прямиком на домашнюю страницу ресурса. Попробуем!



К моему удивлению, сработало! Теперь у нас внутри iframe есть домашняя страница YouTube…или, по меньшей мере, представляющая её страница с ошибкой. YouTube, как и множество современных веб-приложений, запрещает фрейминг большинства своих страниц в целях предотвращения атак по типу «кликджекинга» (clickjacking). Естественно, страница /embed/ относится к исключениям, поскольку предназначена для встраивания на другие сайты, но есть ли другие интересные страницы www.youtube.com, которые мы могли бы встроить во фрейм?



Я поизучала этот вопрос и нашла множество доступных для фрейминга ресурсов на /s/. Мы можем использовать внутри презентации такие элементы, как эмодзи YouTube и исходный код CSS/JS. К сожалению, пока эта возможность не выглядит особо полезной — просто забавный трюк, который мы можем проделать.

▍ Часть 2: перенаправление


Открытые перенаправления (Open Redirect) — это такой вид «уязвимостей», когда веб-приложение может перенаправлять тебя на другую страницу без должной проверки. Например, посещение google.com/url?q=https://lyra.horse1 перенесёт вас на lyra.horse. Но они редко рассматриваются как реальные уязвимости, поскольку их влияние весьма ограничено — вы просто перенаправляетесь с одной страницы на другую.

Тем не менее, поскольку мы привязаны к iframe на youtube.com, открытое перенаправление будет прекрасно работать. Возможность направлять iframe Slides на любой сайт позволит нам проворачивать интересные штуки. Так что поищем, как это сделать.

Первым очевидным местом для поиска будут внешние ссылки сайта — как в описаниях видео и комментариях. И действительно, клик по ссылке в описании видео перенаправляет нас на особую конечную точку /redirect:

https://www.youtube.com/redirect?event=video_description&redir_token=QUFFLUhqbjdTaFRBeHRfSW95bkJDVmRGcl96VXV6MkNmd3xBQ3Jtc0tuOVg2b2ZsQVV6V3hpaUJfdXB0UWY2Z1A1bE1sUjlQeHZ4WlVYSzNVUXZBcUF0RFYzNHhLazVUUVFQM1Y5N3VGZEV4bmtCVWhmYXRwY05KWlEyY0w3ZHBBdDY5SEtBa1hpQXBkalpqT3liYzFqYVZxSQ&q=https%3A%2F%2Flyra.horse%2F&v=tbYxAFHnzG0

Сейчас перенаправление работает, но вы заметите, что здесь есть параметр redir_token — это своеобразный токен для перенаправлений, уникальный для вашего сеанса. Если ту же ссылку откроет кто-то другой, он увидит уже другую страницу:



Будет трудно убедить кого-то кликнуть по такой странице — и даже в этом случае мы всё равно не сможем использовать её внутри нашего iframe из другого источника (cross-origin), так как в ней заголовок x-frame-options установлен на SAMEORIGIN.

Следующим очевидным местом для поиска открытых перенаправлений обычно выступает поток аутентификации сайта — обычно сайты хотят вернуть вас на ту же самую страницу, где вы находились до авторизации. И в случае YouTube всё аналогично — авторизация в аккаунте Google переносит вас обратно на страницу, где вы находились изначально. Реализуется это через конечную точку /signin:

www.youtube.com/signin?action_handle_signin=true&app=desktop&hl=en&next=https%3A%2F%2Fwww.youtube.com%2F&feature=passive&hl=en

Эта точка выполняет перенаправление без использования токена верификации. Мы можем просто указать нужный нам URL в следующем параметре, и всё сработает. Попробуем на моём сайте.



Похоже, это никак не позволяет нам выполнять открытое перенаправление. Следом я попробовала google.com — та же ошибка. Попробовала youtube.com… и снова эта ошибка.

После я вспомнила, что поддомен — www.youtube.com — фактически с перенаправлением работает. Чуть позже я также поняла, что перенаправления работают с любым поддоменом YouTube — сработали и music.youtube.com, и admin.youtube.com! Мы по-прежнему привязаны к доменам YouTube, но теперь у нас хотя бы есть поверхность атаки, с которой можно работать.

▍ Часть 3: пере-перенаправления


И это открытое перенаправление /signin было не единственным, которое я обнаружила — на другом поддомене YouTube присутствовала ещё одна такая уязвимость:

https://accounts.youtube.com/accounts/SetSID?ssdc=1&sidt=&continue=https%3A%2F%2Fwww.google.com&tcc=1&dbus=EE

Это, по всей видимости, авторизация в аккаунте Google. Например, если вы авторизуетесь на google.ee, то будете перенаправлены через accounts.google.com и accounts.youtube.com для обновления куки на обоих. Я здесь немного поэкспериментировала и выяснила, что это снова оказалось неполное перенаправление. Оно позволяло использовать в параметре continue другие собственные домены Google, включая сервисы вроде Docs.

Если бы мы могли перенаправить наш iframe на docs.google.com, это бы открыло перед нами широкие возможности. Google Docs построен так, что у большинства страниц ресурса заголовок x-frame-options установлен на SAMEORIGIN. То есть у нас не должно быть возможности вставлять эти страницы во фреймы на других сайтах. Тем не менее, имея подобную возможность перенаправления, мы получим внутри Slides iframe с тем же источником (same-origin), что позволит нам вставлять во фреймы, казалось бы, недопустимые страницы и проделывать на них всякое интересное.

Попробуем привязать наше предыдущее перенаправление /signin к новому адресу accounts.youtube.com и посмотрим, удастся ли встроить страницы Docs внутрь них самих.



И вуаля — мы получили Docs внутри Docs. Эпично!

▍ Часть 4: хорошо, но что дальше?


Итак, у нас есть Docs внутри Docs, что очень веселит, но всего несколько минут. А можем ли мы реально проделать с этим что-то полезное? Я немного поигралась с домашней страницей Docs, но единственным интересным взаимодействием оказалось удаление документа, да и в этом случае его всё равно можно восстановить из корзины. Нужно найти что-то более влияющее на домен Docs.

Вы можете решить, что полезными окажутся сами страницы редактирования документов, но они уже защищены, поскольку изначально (по задумке) доступны для встраивания во фреймы на внешних сайтах. Если страница обнаруживает, что находится внутри iframe, то отключает множество опасной функциональности, например, возможность расшаривать документ.

Вот на этом этапе я разбиралась дольше всего. Я долго искала на домене docs.google.com что-нибудь интересное для фрейминга и кликджекинга. Просматривая Wayback Machine2 и пробуя различные Google Dorks3, я продолжала находить множество старых конечных точек, которые могли стать полезными в прошлом, но теперь перенаправляют на Google Drive, где фрейминг недоступен.

Переходя по ссылке за ссылкой, я в итоге наткнулась на URL docs.google.com/file/d/{ID}/edit. На этой странице можно открывать предпросмотр и совершать различные действия (например, делится чем-либо) в Google Drive. И, в отличие от других ранее встреченных мной ссылок, она вместо перенаправления на Drive остаётся на домене docs.google.com. И она не только работает с файлами Drive, но также с каталогами и прочими подобными сущностями (например, страницами Google Sites). Вы можете даже открывать с её помощью свой «корневой» каталог на Drive4!



На странице есть кнопка «Share», которая остаётся активной даже внутри iframe. Если мы хитростью заставим кого-нибудь кликнуть по этой кнопке, ввести e-mail и изменить разрешения для какого-то важного каталога, то получим к нему доступ.

▍ Часть 5. Но можем ли мы это?


Начнём с проверки нашей затеи на реализуемость — можем ли мы реально заставить кого-нибудь выполнить все перечисленные действия? Возможно, при достаточных усилиях, но даже со всеми нашими способностями к фреймингу и кликджекингу, потребуется проделать многое, чтобы убедить человека выполнить это. Я не думаю, что коллегия VRP5 будет особо впечатлена столь сильным упором на социальную инженерию. Нам нужно найти способ сделать процесс более убедительным — в идеале сведя его до одного клика.

Обдумывая способы улучшения этой атаки, я вспомнила о функции Drive, которая позволяет вам запрашивать доступ к документам других людей. Это действие приводит к отправке e-mail с кнопкой для непосредственного управления разрешениями.



Кнопка в этом e-mail связана со ссылкой https://drive.google.com/drive/folders/{ID}?usp=sharing_esp&userstoinvite=lyra.horse@gmail.com&sharingaction=manageaccess&role=writer&ts=66e724ba, которая при открытии выводит диалоговое окно «Share» с уведомлением о запросе. Естественно, это ссылка на Drive, а не Docs, но я попробовала скопировать все параметры запроса в ссылку Docs, и это сработало.



В своём текущем состоянии страница для выполнения атаки требует двух кликов — сначала по вкладке «Review» и затем по кнопке «Share». И это уже довольно неплохо, но я всё ещё реально хочу свести реализацию атаки до всего одного клика.

Я расчехлила свои DevTools и начала копать JS-код страницы, чтобы понять, как обрабатываются параметры запроса. В качестве простой проверки я начала с параметра userstoinvite.



И «Вау»!? Я случайно обнаружила URL идеального окна «Share». По какой-то причине, если не указаны все прочие параметры запроса, это окно просто автоматически заполняет поле e-mail из параметра запроса, по умолчанию выдавая разрешения уровня Editor.

Теперь нам нужно лишь убедить кого-нибудь сделать один клик по кнопке «Send» с двусмысленным названием, и дело сделано!

▍ Часть 6: пере-пере-перенаправления


Я начала формировать атаку, объединив все классные трюки, которые нашла ранее.

  1. Сначала берём скромный пригласительный URL в Google Docs.
    docs.google.com/file/d/1sHy3aQXsIlnOCj-mBFxQ0ZXm4TzjjfFL/edit?userstoinvite=lyra.horse@gmail.com
  2. Помещаем его в перенаправление accounts.youtube.com.
    accounts.youtube.com/accounts/SetSID?continue=https%3A%2F%2Fdocs.google.com%2Ffile%2Fd%2F1sHy3aQXsIlnOCj-mBFxQ0ZXm4TzjjfFL%2Fedit%3Fuserstoinvite%3Dlyra.horse%40gmail.com
  3. Затем помещаем его в перенаправление youtube.com/signin.
    www.youtube.com/signin?next=https%3A%2F%2Faccounts.youtube.com%2Faccounts%2FSetSID%3Fcontinue%3Dhttps%3A%2F%2Fdocs.google.com%252Ffile%252Fd%252F1sHy3aQXsIlnOCj-mBFxQ0ZXm4TzjjfFL%252Fedit%253Fuserstoinvite%253Dlyra.horse%2540gmail.com
  4. И, наконец, превращаем всё это в videoid, который сможем встроить в наши слайды.
    ../signin?next=https%3A%2F%2Faccounts.youtube.com%2Faccounts%2FSetSID%3Fcontinue%3Dhttps%3A%2F%2Fdocs.google.com%252Fa%252Fa%252Ffile%252Fd%252F1sHy3aQXsIlnOCj-mBFxQ0ZXm4TzjjfFL%252Fedit%253Fuserstoinvite%253Dlyra.horse%2540gmail.com

Готово! Я добавила его в слайды, и…



…Не сработало. Но почему?

Похоже, что в Google Docs реализован какой-то механизм защиты, не дающий мне использовать межсайтовое перенаправление для страницы файла внутри iframe. Говоря точнее, он проверяет заголовки Sec-Fetch-Dest и Sec-Fetch-Site — если они установлены на iframe и cross-site соответственно, возвращается статус 403. Довольно странно.

У меня была возможность пообщаться с парой безопасников из Google. Я спросила их об описанном поведении, и похоже, что это своеобразное средство противодействия, позволяющее предотвратить cross-origin фрейминг на стороне сервера. Я до сих пор не уверена, в каком сценарии угроз это будет полезно, но идея в том, чтобы iframe мог понять, находится ли он на странице того же источника (same-origin), только по заголовку Sec-Fetch-Site. На странице другого источника (cross-origin) заголовок всегда будет установлен на cross-site, даже если перенаправление внутри iframe будет иметь тот же источник.

Естественно, это можно обнаружить более надёжно на клиентской стороне с помощью JS-кода и всего такого, но заголовки являются единственным способом для сервера понять это до отправки ответа. Побочный эффект обнаружения на стороне сервера в том, что хоть оба наших фрейма и имеют одинаковый источник, перенаправление между ними внутри iframe всё равно будет иметь заголовок cross-site. Чтобы это обойти, нужно выполнить в iframe перенаправление внутри одного источника.

Проще говоря, сейчас мы делаем так:

accounts.youtube.com (межсайтовый переход) → docs.google.com/file/d/…/edit (403)

И чтобы это обойти, нам потребуется связать перенаправления так:

accounts.youtube.com (межсайтовый переход) → docs.google.com/??? (тот же домен) → docs.google.com/file/d/…/edit (200)

Должно сработать! Но нам нужно найти что-то, что сработает для части в середине. И, к счастью для нас, я уже подметила в интернете подходящее решение.

Похоже, что у docs.google.com/a/<domain>/… есть какой-то старый легаси-формат URL GSuite, который раньше наверняка делал что-то полезное (да и до сих пор делает6), но сегодня при открытии URL просто исчезает. Если вы не авторизованы, то вам понадобится найти URL-донора, например, /a/wyo.gov/7. Если же вы авторизованы, то можете даже использовать /a/a/, и всё заработает.

Вот пара примеров URL для пробы.

Этот должен работать вне зависимости от состояния авторизации:

docs.google.com/a/wyo.gov/file/d/10LlimFowOJ_noDrJsv4CnRgU8XoUKRAa6YjTeJFrs70/edit

А этот потребует быть авторизованным в любом аккаунте Google:

docs.google.com/a/a/file/d/10LlimFowOJ_noDrJsv4CnRgU8XoUKRAa6YjTeJFrs70/edit

Оба приведут к перенаправлению на:

docs.google.com/file/d/10LlimFowOJ_noDrJsv4CnRgU8XoUKRAa6YjTeJFrs70/edit.

Разобравшись с этим, добавим /a/a/ в наш videoid:

../signin?next=https%3A%2F%2Faccounts.youtube.com%2Faccounts%2FSetSID%3Fcontinue%3Dhttps%3A%2F%2Fdocs.google.com%252Ffile%252Fd%252F1sHy3aQXsIlnOCj-mBFxQ0ZXm4TzjjfFL%252Fedit%253Fuserstoinvite%253Dlyra.horse%2540gmail.com



Сработало!

▍ Часть 7. Финишные штрихи


Разместив диалоговое окно «Share» внутри презентации, нам осталось лишь наложить на него разные штуки, чтобы сделать его более презентабельным. Поскольку нам лишь нужно, чтобы кто-нибудь кликнул по кнопке «Send», я решила сделать своё демо похожим на Google Forms.



И готово! Выглядит как страница Google Forms, но содержит «вырезку» для кнопки «Send» в диалоговом окне «Share» ниже. Если по ней кликнуть, она сразу же выдаёт для целевого файла/каталога разрешения уровня Editor с указанным e-mail.

Чтобы отправить эту атаку кому-либо, мы можем заменить /edit на /present в URL Slides, чтобы она открывала и «воспроизводила» слайд непосредственно.

И вот результат — готовая атака по типу «кликджекинга» из одного клика, которая связывает путь встраивания Google Slides с тремя раздельными перенаправлениями для получения редакторского доступа к каталогу/файлу на Drive.

Я сообщила об этой цепочке уязвимостей в Google 1-го июля 2024 года, и в тот же день получила её подтверждение. Спустя 10 дней, а именно 11 июля коллегия VRP выдала мне заслуженную награду в виде $3133.70 + $1000 бонусом, итого $4133.70. Очень приятно!

▍ Послесловие


Благодарю вас за чтение! Вы великолепны!

Я старалась писать сжато, поскольку также представлю эти свои исследования с дополнительными элементами истории на конференции BSides Tallinn 2024 в день выхода статьи. Надеюсь, всё пройдёт хорошо! Не уверена, когда будут выпущены записи с выступлений на конференции (следите за этим каналом), но пока что можете посмотреть слайды.

Как и в случае с моими предыдущими статьями, всё на данной странице — это просто HTML/CSS, написанный с любовью (имеется в виду оригинал статьи, — прим. пер.). Никаких изображений, JS-кода или прочих внешних ресурсов, и общий размер всего 31 КБ в формате GZIP (5 секунд передачи по коммутируемой линии). Это требует много сил и времени в сравнении с простым выкладыванием скриншотов на страницу, но мне очень нравится оживлять статью таким образом — добавляя в неё интерактивность и прочее. Причём выходит она вполне отзывчивой!

Надеюсь, что текст получился согласованным и интересным. Разработанная мной цепочка атаки включает множество элементов, поэтому статья местами запутана. Но в случае неясности вы всегда можете задать мне любые вопросы ^^

Всех люблю <3!

Обсуждение этой статьи на: twitter, mastodon, lobsters (покойся с миром, cohost :c)


  1. Конкретно этот пример будет, скорее, выводить предупреждение — но давайте представим, что не будет. ↩︎
  2. Internet Archive позволяет перечислять все архивные URL домена, что довольно удобно для разведки. ↩︎
  3. Dorks — это различные операции поиска и приёмы, которые вы можете использовать в Google, например site:docs.google.com или inurl:document. ↩︎
  4. С каждым файлом и каталогом на Google Drive ассоциирован ID, и весь ваш корневой (Root) каталог диска не исключение. Хотите найти свой? Откройте страницу Drive при запущенных DevTools и отыщите 9PVA в сетевых запросах. ↩︎
  5. VRP — это программа Google по охоте на баги. Её коллегия решает, сколько $$$ вы получите за обнаружение бага. ↩︎
  6. advaith, дай знать, переключает ли URL /a/domain автоматически твой аккаунт на находящийся в указанном домене. Это подтвердит удобство таких адресов при использовании нескольких аккаунтов. ↩︎
  7. Я до сих пор использую этот домен в качестве примера, поскольку он короткий и встречался во многих моих исследованиях, хотя по факту в нём нет ничего особенного — вы можете использовать и другие домены. ↩︎

Telegram-канал со скидками, розыгрышами призов и новостями IT ?

Комментарии (3)


  1. ArtyomOchkin
    27.09.2024 16:02

    Спасибо, очень любопытно!

    Надо будет на досуге покопать что-нибудь такое, интересная тема!


  1. echo0x00
    27.09.2024 16:02
    +1

    У меня была возможность пообщаться с парой безопасников из Google

    Неплохой такой способ баг хантинга


  1. DenKaGamer
    27.09.2024 16:02

    Ого, интересная статья, жаль не хватает кармы на то чтобы плюсик поставить посту... :(