Clickjacking DOM XSS на картах от Google

Clickjacking DOM XSS на картах от Google

Moody

Один из наименее известных проектов Google - Google Crisis Map.

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

Не смотря на то, что он все еще работает, кажется, что о нем все уже забыли и никто не пользуются.

Поскольку это достаточно старый (созданный в 2012 году) и редко обновляемый проект, он становится отличной мишенью для поиска уязвимостей.

Сайт размещен в домене google.org, который не имеет такой критичности, как google.com (для client-side уязвимостей), но по-прежнему принадлежит этой гигантской корпорации - это значит, что любой, кто найдет на нем баг, с вероятностью 99% получит выплату.

Вход в систему

Если вы откроете домашнюю страницу проекта (google.org/crisismap), перед вами откроется карта «Погода и события». Она нас особо не интересует, так как единственное, что мы можем с ней сделать, это просто посмотреть на нее.

На этом сервисе есть также возможность управлять и создавать собственные карты. Доступ к ней можно получить, если мы добавим .maps в конце URL: google.org/crisismap/.maps

Открыв эту страницу, вас скорее всего редиректнет на страницу авторизации в Google. А если вы уже авторизованы, то попадете в панель со списком карт. По умолчанию, у каждой новой учетной записи, существует 3 таких карты.

По какой-то причине, если вы опубликуете одну из этих карт на своем собственном домене, это сможет увидеть каждый в своей панели инструментов под надписью «Published Map».

Создание карты

Если вы нажмете красную кнопку «Создать карту», то скорее всего увидите сообщение о том, что домен gmail.com не может быть использован для создания новых карт.

Это означает, что нам нужно войти в систему, используя электронную почту с доменом, отличным от google.com. Самый простой способ сделать это - войти в систему под учетной записью GSuite. После авторизации, мы, наконец, можем приступить к созданию собственной карты.

Поиск XSS

Во-первых, давайте создадим и добавим новый слой на карту.

В качестве названия, можно указать абсолютно любую строку (там санитизация работает исправно).

А если ввести в поле «Source URL» строку javascript:alert(document.domain), появится сообщение об ошибке:

Invalid URL – please include a protocol (e.g. http:// or https://)

Это означает, что сайт проверяет, является ли URL действительным, прежде чем позволить вам сохранить новый слой. Деобфусцированный JavaScript-код, который проверяет URL, выглядит следующим образом:

if (url && !url.toLowerCase().match("^\\s*(http://|https://|docs://|$)")) {
  showError("Invalid URL - please include a protocol (e.g. http:// or https://)");
}

Но это лишь проверка на стороне клиента перед тем, как фактический запрос на сохранение будет отправлен на сервер.

Модификация запроса

Мы можем использовать прокси-сервер для отладки, такой как Fiddler или Burp Suite, чтобы изменить запрос и отправить вместо него измененную версию.

Во-первых, нам нужно изменить «Исходный URL» на действительный URL, например, https://example.com.

После этого нажать на кнопку «ОК», затем «Сохранить», чтобы отправить запрос на сохранение и перехватить его.

POST https://google.org/crisismap/.api/maps/1234

{
  "id": "1234",
  "title": "Untitled map",
  "base_map_type": "GOOGLE_ROADMAP",
  "layers": [{
    "id": "1",
    "title": "Test layer",
    "visibility": "DEFAULT_ON",
    "type": "KML",
    "source": {
      "kml": {
        "url": "https://example.com"
      }
    }
  }]
}

Мы заменим https://example.com на javascript:alert(document.domain) и отправим этот измененный запрос.

Тестирование XSS

Запрос отправлен и сохранен, поэтому мы перезагрузим страницу.

Теперь открываем «Слои» и нажимаем «Download KML».

Запускается XSS и... появится окно с именем домена!

Фикс

Почему это случилось? Проверка URL произошла только на внешнем интерфейсе, а не на внутреннем. Это означает, что баг можно исправить, проверив URL-адрес на серверной части.

Но это не тот путь, по которому пошел Google. Вместо проверки URL при сохранении его в бэкэнде, URL теперь проверяется перед отображением в DOM.

Поэтому, если URL-адрес недействителен, он не будет использоваться в качестве ссылки. Вместо этого будет использоваться бессмысленное значение, например about:invalid.

<a href="about:invalid#zClosurez">Download KML</a>

Импакт

Итак, у нас есть ссылка, которая указывает на javascript: URI, содержащий полезную нагрузку. Ссылка находится на странице для управления картой. И вы должны войти в систему и иметь разрешение на доступ к этой странице.

Ясно, что это self-XSS, так как только мы можем выполнить этот XSS.

Теперь, как нам перейти от self-XSS к настоящему XSS?

Апгрейд критичности

Каждая карта, которую мы создаем, может быть опубликована для просмотра другими людьми. Если вы вошли в систему по электронной почте с доменом example.com, вы можете опубликовать карту по адресу http://google.org/crisismap/example.com/test.

Любой может открыть этот URL и просмотреть созданную нами карту. Чтобы заставить XSS работать, пользователь должен открыть или перейти на эту страницу, открыть «Слои» и затем щелкнуть ссылку «Скачать KML».

Это означает, что уязвимость больше не будет считаться Self-XSS, но пользователю все равно придется сделать слишком много шагов, чтобы этот XSS был полезным.

Clickjacking

Если мы посмотрим на HTTP-заголовки ответа, то увидим, что google.org не отправляет заголовок X-Frame-Options.

HTTP-заголовок ответа X-Frame-Options можно использовать, чтобы указать, следует ли разрешить браузеру отображать страницу в <frame>, <iframe>, <embed> или <object>. Сайты могут использовать это, чтобы избежать Clickjacking атак, гарантируя, что их контент не будет встроен в другие сайты.

Отсутствие этого HTTP-заголовка на google.org означает, что мы можем встроить опубликованную карту в iframe на нашем собственном веб-сайте.

<iframe src="https://google.org/crisismap/example.com/test"></iframe>

Вот так это будет выглядеть. Чтобы запустить XSS, пользователю теперь даже не нужно покидать наш веб-сайт. Но ему все равно нужно щелкнуть два места в iframe («Слои»> «Загрузить KML»).

iframe загружается на нашем сайте - это означает, что мы можем использовать CSS и JavaScript для манипулирования им.

Первое, что пришло мне в голову, это поместить черный DIV в точку, куда должен нажать пользователь. Затем обнаружить щелчок и переместить DIV во вторую точку.

Это работает отлично, но все равно требует двух кликов (в два разных места).

Более эффективным решением было бы разместить iframe на весь экран, чтобы пользователю вообще не приходилось перемещать курсор.

Выводы

Здесь можно выделить сразу несколько вещей:

  1. Никогда не доверяйте пользовательскому вводу. Всегда проверяйте / избегайте его перед использованием.
  2. Не позволяйте другим доменам встраивать ваш сайт в iframe, правильно установив заголовок X-Frame-Options.
  3. При поиске уязвимостей постарайтесь выжать максимум критичности из своей уязвимости.
  4. Например, если вы найдете XSS, попробуйте перехватить при помощи нее учетную запись, обнаружив неправильно настроенные файлы cookie или новые эндпоинты.
  5. Ищите старые проекты, которые все еще вписываются в сферу действия программы Bug Bounty. Я обнаружил еще две уязвимости в Google Crisis Map, о которых также будет написано.


Статья доступна в оригинале на английском языке - читать.

Cybred - канал об информационной безопасности и конкурентной разведке, вдохновленный идеями олдскульных андеграундных интернет-сообществ о свободе распространения информации в сети и всеобщей взаимопомощи.

Report Page