Как-то вечером я решил исследовать безопасность Facebook. После недолгого хождения по порталу мой взгляд зацепился за Graph API Explorer. Это веб-приложение для работы с Facebook Graph API, которое позволяет получать пользовательские данные от Facebook и загружать их на Facebook. Конечно, многие операции доступны только при наличии OAuth-токена. Что же это приложение на самом деле делает?
Когда пользователь делает какой-либо запрос на получение или отправку данных, приложение посылает JSONP-запрос на graph.facebook.com
, при этом добавляя callback, который будет отрисовывать полученные данные на странице. Первым делом я попытался подменить этот callback на что-то свое (подробнее об этом методе), — но безуспешно, так как callback-параметр, который я внедрял, просто отбрасывался. После нескольких неудачных попыток внедрить callback я вспомнил об одной интересной странице — "login.php"
, на которую наткнулся в процессе исследования Facebook. Эта страница встречалась на всех доменах и позволяла выполнить redirect на любую страницу любого поддомена facebook.com
. Для начала я попробовал сделать redirect на тот же graph.facebook.com
, но со своим callback-параметром.
https://developers.facebook.com/tools/explorer?method=GET&path=login.php?next%3dhttps%253a//graph.facebook.com/me%253fcallback%253dalert
Я увидел заветное окошко с текстом [Object object]
, которое свидетельствовало, что мой callback исполнился. Но я, конечно же, не мог на этом остановиться. Теперь я занялся поиском места в Facebook, где я мог бы сохранить свой JavaScript-код, чтобы потом его исполнить. Первое, что пришло мне в голову, — отправить файл с сообщением какому-либо пользователю, подменив Content-Type на text/javascript. После этого мы получаем ссылку вида
https://www.facebook.com/ajax/messaging/attachment.php?attach_id=<ID>&mid=<MID>&hash=<HASH>
которая перенаправляет нас на
https://attachment.fbsbx.com/messaging_attachment.php
, где хранится наш код. Этот код доступен только для отправителя и получателя сообщения, но, как известно, злоумышленник может сделать GIF-изображение, которое будет содержать в себе JavaScript-код (пример). Злоумышленник может отправить такой GIF-файл жертве, получить ссылку на него и использовать затем эту ссылку для эксплуатации уязвимости. Жертва в свою очередь увидит только картинку и не заметит ничего подозрительного.
Итак, пробуем исполнить наш код… Ничего не вышло. Дело в том, что Facebook указывает заголовок "content-security-policy"
, который позволяет браузеру выполнять только JavaScript, полученный от определенных доменов. Я расстроился и уже начал искать другое место для хранения своего кода, как вдруг вспомнил, что Internet Explorer игнорирует этот заголовок. Вместо него он требует заголовок "x-content-security-policy"
. Пробуем исполнить наш код в IE10 и видим следующий результат:
Ура! Код исполнился. Я сообщил об этой уязвимости в Facebook, и она была довольно быстро исправлена, а я не удержался от того, чтобы сделать скриншот.
Видео эксплуатации:
Автор: Павел Топорков, Positive Research.
Автор: ptsecurity