При обращении к сайту с Google Analytics, сценарий обрабатывает значение HTTP заголовка Referer и извлекает из него host и путь к сценарию, для отслеживания откуда пришел пользователь. В дальнейшем эти данные попадают в cookie параметр .
Выглядит это следующим образом: Изменяя путь к сценарию на своем сайте, с которого пользователь переходит на сайт с Google Analytics, можно влиять на конец значения cookie и попытаться изменить атрибуты cookie, так как путь никак не обрабатывается перед попаданием в значение. Однако, атрибуты будут перезаписаны последующими значениями, которые подставляет Google Analytics. Результат: На данный момент это было сложно назвать уязвимостью, но тем не менее поведение сценария довольно интересное, к тому же он невероятно распространен.
Bug Bounty и Cookie
Небольшое отступление. Уязвимости, связанные с cookie, в рамках программ вознаграждения за уязвимости, примечательны тем, что у вас может получится два основных сценария:
Найдена возможность перезаписи и создания произвольных cookie параметров.
Ответ: Это всего лишь cookie, что это тебе даст?
Найдена XSS через cookie параметр.
Ответ: Ты ведь не можешь создать произвольный cookie параметр, значит, это не уязвимость!
И только если оба варианта оказались в рамках одной Bug Bounty программы, то вам, так уж и быть, заплатят.
Необходимость каждый раз доказывать угрозу от проблем, связанных с сookie, зачастую отталкивает людей от их поиска. Так как за потраченное на это время можно найти еще десяток уязвимостей, которые будут приняты без вопросов. В основном проверяются только самые базовые вещи, типа фиксации сессии и правильности установленных атрибутов secure, httpOnly…
Cookie
Взглянем на структуру сookie заголовков:
Структура довольно сложная и с ней работают при каждом запросе браузер, JavaScript сценарии и веб-сервер. Каждый при этом обрабатывает по-своему, и одна и та же строка может дать разные результаты.
Анализируя обработку cookie необходимо задаться следующими вопросами:
Нужны ли пробелы после ; Какие символы можно использовать вместо ; Какое значение будет результирующее в случае одинаковых ключей Важен ли регистр у ключей Сколько может быть атрибутов у параметра Какое значение будет результирующее в случае одинаковых атрибутов Как правильно кодировать спецсимволы
Особенности обработки Cookie
Первая и наиболее известная особенность — Safari позволяет объявлять несколько параметров через один заголовок Set-Cookie. Возвращаясь к проблеме Google Analytics, проверим данную особенность в установке cookie через JavaScript. Получаем первый вариант эксплуатации: Результат Safari создаст два cookie параметра и .
То есть, для пользователя Safari на любом сайте с Google Analytics можно создать произвольный cookie параметр. Осталось только придумать зачем…
CSRF
Защиту от CSRF можно условно разделить на 3 типа:
Различные токены для каждого действия. Хранятся на сервере. Один сессионный токен на все действия. Хранится на сервере в сессии пользователя. Один сессионный токен на все действия. Хранится в cookie параметре.
Третий вариант основывается на том, что значение токена в cookie пользователя недоступно для злоумышленника. Для прохождения проверки достаточно просто послать одинаковое значение токена в cookie и post параметрах. То есть, простая перезапись значения через Google Analytics тут подойдет идеально.
Особенности обработки Cookie #2
Что если развернуть атаку на 180 градусов? Не обязательно, чтобы в браузере действительно был cookie параметр с CSRF токеном, значение которого мы знаем. Достаточно, чтобы так считал веб-сервер.
В этом поможет еще одна обнаруженная особенность обработки сookie. Note: For backward compatibility, the separator in the Cookie header
is semi-colon (;) everywhere. A server should also accept comma (,)
as the separator between cookie-values for future compatibility.
Многие веб-серверы поддерживают перечисление сookie не только через точку с запятой, но и через запятую.
Более того, в некоторых случаях пробел не обязателен.
В свою очередь, для большинства браузеров такие символы как пробел и запятая являются вполне нормальными. И если установить:
Для браузера это будет одно значение, но для некоторых серверных реализаций — два сookie параметра. Однако, в случае эксплуатации данных особенностей для обхода CSRF защиты, необходимо помнить, что мы не перезаписываем старый токен, а добавляем еще один, то есть важен порядок обработки сookie. Итого получается уже две цепочки эксплуатации уязвимости:
Эксплуатация
После подготовки неплохой базы, необходима проверка в реальных условиях. Практически сразу находится идеальный вариант .
На нем реализована CSRF защита, основанная на cookie, сервер поддерживает перечисление cookie через запятую без пробела, но… На нем нет Google Analytics. Зато он есть на ! Самое время проверить обработку атрибутов cookie значений, а если точнее, проверить возможность отбрасывания добавляемых в конце значений path и domain в случае, если инъекция происходит в значение cookie.
Оказалось, что Google Chrome в случае большого количества атрибутов cookie в какой-то момент просто прекращает их разбирать и не доходит до последних валидных значений.
То есть, в данном случае: Cookie будет установлена на , а не на .
Таким образом, добавляется еще одна цепочка эксплуатации: Формируем PoC: Описание:
Пользователь авторизован на Мобильная версия подхватывает сессию основного сайта даже если пользователь не заходил на нее Предполагаем, что пользователь не был на и у него не установлена cookie на нем Передаем Referer с путем, в котором содержится инъекция в cookie, на сайт Google Analytics создает сookie Из-за большого количества атрибутов Chrome перезаписывает domain на Ждем окончание обработки запроса и посылаем еще один запрос на создание твита «PoC», используя токен «x» В соответствии с порядком отправленных cookie, берет наше значение токена «x» и убеждается, что значение в post запросе и в cookie одинаковые У пользователя появляется твит PoC
Особенности обработки Cookie #3
Следующей целью стал , а точнее все сайты на Django. CSRF защита в Django также основана на cookie. Для успешного прохождения проверки достаточно послать одинаковые значения в cookie и post параметре , либо в HTTP заголовке . Однако, есть дополнительная проверка, которая в дальнейшем может помешать. В случае, если сайт работает по HTTPS, Django проверяет заголовок Referer и, в случае несовпадения, блокирует запрос, даже если в нем указан правильный токен. Post запросы без Referer также блокируются.
В ходе изучения обработки сookie в Django были обнаружены следующие особенности:
В качестве разделителя не обязательно использовать точку с запятой, достаточно любого пробельного символа между параметрами
Если в значении сookie есть символы , то первая часть сookie отбрасывается
.
В результате создается только сookie .
Оказалось, что данная проблема даже не в Django, а в Python. Библиотека Cookie обрабатывает значения в соответствии с . И действительно оказывается, что использование символов не предусмотрено, если значение не обрамлено двойными кавычками. Для браузеров же использование этих символов — вполне нормальное явление.
PoC для instagram практически идентичен предыдущему: Для пробрасывания cookie используется , а для создания токена конструкция .
Особенности обработки Cookie #4
После общения с Google, Twitter, Facebook, Django и Python я вновь решил попробовать обойти их исправления.
Произошли следующие изменения условий:
Google Analytics начал отбрасывать часть после точки с запятой и принудительно заменять пробел на %20 Python исправил некорректную обработку
Однако, все еще оставалась возможность перечисления cookie через пробельный символ в Django, чему сильно мешала замена используемая Google.
Проверка пробельных символов показала следующее:
Internet Explorer заменяет символы \x09 \x0b \x0c на _ Chrome не устанавливает cookie, если оно содержит символы \x09 \x0b \x0c FireFox считает данные символы нормальными
В результате чего получается следующий вариант эксплуатации для FireFox Особенности обработки Cookie #5
Также я обнаружил еще один интересный вариант в некоторых серверных реализациях, но пока не нашел применения в реальных условиях. При использовании спецсимволов в cookie, значение обрамляют в двойные кавычки. Данное поведение можно использовать следующим образом:
Для браузеров двойные кавычки не являются каким-то особым символом и в результате получится такой заголовок: Но некоторые веб-серверы могут обработать данные значения, как один параметр test, в результате чего параметр не будет создан. При совпадении невероятного количества условий, данная особенность также может быть использована.
Результаты
Варианты эксплуатации
Фиксы
В Google Analytics добавили принудительную замену пробела на %20 в значении cookie (сомнительное улучшение)
В Google Analytics исправили возможность изменить атрибуты cookie путем отбрасывания всего, что идет после символа ";"
Google Chrome НЕ будет исправлять перезапись с помощью большого количества атрибутов, так как возможности устанавливать произвольные атрибуты не должно быть у клиента изначально
Python исправил проблему с символами ()
Twitter изменили тип CSRF защиты на сайте
При общении с Google я столкнулся с тотальным непониманием сути уязвимости. От меня требовали примера на сайтах Google, которого у меня не было, и их совершенно не интересовало, что Google Analytics может нести угрозу на других сайтах. И лишь спустя десяток писем мой отчет попал к Krzysztof’у (судя по всему это был ), который разобрался что к чему и донес информацию до соответствующих разработчиков.