Microsoft Edge – Универсальный XSS

@
Перевод статьи подготовлен специально для студентов курса «Реверс-инжиниринг».




Универсальный XSS (uXSS) – это баг браузера, который дает возможность выполнять код на JavaScript на любом сайте.

Кажется, будто XSS есть на всех сайтах и выглядит это очень интересно. Что еще интереснее, так это то, как я нашел эту ошибку. Обычно, если речь заходит о uXSS, то это скорее всего связано с элементом IFRAME или возней с URL, но я никогда не думал, что найду XSS-уязвимость, используя функцию print().

Окно предварительного просмотра


Давайте поговорим о том, что на самом деле происходит, когда Edge отображает окно предварительного просмотра печати.

Я всегда думал, что там находится просто скриншот, отрисованный технологией типа Canvas, но на самом деле страница, которую вы собираетесь печатать, копируется в temp и повторно рендерится!

Когда на странице выполняется print(), мы видим следующую активность файловой системы в Process Monitor:



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

Перед печатью:

   Printer Button   Print!     

После печати:

   Printer ButtonPrint!    

Есть несколько вещей, которые мы можем заметить из этого сравнения.

  1. Javascript кодируется и рендерится неправильно.
  2. Теперь IFRAME указывает на другой локальный файл в той же самой директории, которая содержит исходный код оригинальной ссылки bing.com.
  3. У HTML элемента теперь есть своеобразный атрибут __IE_DisplayURL.

В отношении первого и второго пункта я провел несколько тестов. Сначала я хотел понять, могу ли я получить валидный Javascript-код после смены кодировки, в надежде, что в итоге я смогу выполнить Javascript. Оказалось, что любой код внутри элемента script>, нормальный или нет, выполняться не будет.

Второй пункт помог мне раскрыть имя пользователя операционной системы с помощью функционала @media print{} в CSS и магии селекторов. Я смог получить его из значения IFRAME href. Однако и этого было недостаточно.

Вот на третьем пункте стало интересно, поскольку этот атрибут крайне необычный и до этого момента я с ним не встречался. Я сразу же его загуглил и нашел несколько статей, исходя из которых понял, что некто Масато Кинугава уже поиграл с ним и обнаружил крутые баги.

После чтения и некоторой практики, я обнаружил, что контекст предварительного просмотра узнает из этого атрибута откуда появляется документ. Это имеет смысл, поскольку Edge открывает файлы с помощью file: URI схемы. С помощью этого атрибута, указывающего на источник, вы заметите, что все запросы, поступающие от документа (в рамках предварительного просмотра), будут имитировать точно такое же поведение, как если бы они поступали с исходного веб-сайта.

Как мы можем использовать этот атрибут? Должен же быть какой-то способ!

Выполнение кода на Javascript с помощью предварительного просмотра


Как я уже говорил, любой код на JavaScript, находящийся в нормальном теге script будет заблокирован или просто проигнорирован. Но что если мыслить в другом направлении? Я перепробовал все, что только мог придумать, поэтому избавлю вас от траты времени на множество неудачных попыток и перейду сразу к делу.

Здесь мы имеем дело с функцией печати, поэтому я играл с событиями, относящимися к печати. Результат мне принесло "onbeforeprint", с помощью него я получил возможность внедрять IFRAME, который указывал на любой веб-сайт и Edge не нужно было конвертировать его сначала в файл. Почти сразу я попытался внедрить IFRAME, который указывал на URL-адрес Javascript-кода и та-дам! Этот код выполнялся в контексте предварительного просмотра.

Тест Javascript-инъекции:

   Printer Button   Print! 

После конвертации предварительного просмотра документа:

   Printer ButtonPrint! 

Скриншот результата:



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

Реализация uXSS


Теперь, когда мы умеем внедрять свой исполняемый код, нам нужно каким-то образом создать свой собственный «предварительный просмотр документа» с нашим собственным __IE_DisplayURL, а затем мы сможем сымитировать любой веб-сайт, который выберем для uXSS.

Я обнаружил, что с помощью Blob URL я смогу добиться нужного эффекта! Поэтому я сделал свой собственный документ для печати со своим атрибутом, указывающим на целевой сайт (в моем случае bing.com). Он содержал Javascript IFRAME, который выполнялся, как будто он исходит от bing.com.

Я внедрил следующий код:

if (top.location.protocol == 'file:') { setTimeout(function() { top.location = URL.createObjectURL(new Blob([top.document.getElementById('qd').value], { type: 'text/html' })) }, 1000) }

Где top.document.getElementById('qd').value — это следующий фейковый документ для печати.

      


Все, что я делаю – это читаю document.cookie и отправляю их обратно серверу.
А теперь обобщим то, что делает финальная версия эксплойта:

  1. Используя событие onbeforeprint, я внедряю IFRAME, который указывает на мою полезную нагрузку непосредственно перед печатью.
  2. Для инициализации я вызываю window.print().
  3. Затем Edge отображает окно предварительного просмотра во время рендеринга моего внедренного кода;
  4. Внедренный Javascript-код создал Blob URL-адрес, который содержит мой собственный документ для печати bing.com и перенаправляет верхний фрейм на этот адрес.
  5. Контекст предварительного просмотра печати думает, что содержимое моего Blob URL-адреса – настоящий документ для печати и устанавливает происхождение документа как bing.com с помощью атрибута __IE_DisplayURL.
  6. Фейковый документ для печати сам по себе содержит другой IFRAME, который просто отображает document.cookie источника bing.com.
  7. uXSS работает!

Итоговый код и видео


                    



Полезные ссылки:

Microsoft.com
Анализ
×
Microsoft
Сфера деятельности:Связь и ИТ
118