[Перевод] Microsoft Edge – Универсальный XSS

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

qk6kwn42jwyudahlbsu7_jdkels.png


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

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

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


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

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

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

t4kw2agxhpoqhqlm8sx7s-xtpyw.png

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

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




	Printer Button


















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




Printer 
Button  


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

  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




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




Printer 
Button 


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

nwmoyk_e1jmnmbkarwbuj3krwyo.png

То, что мы умеем выполнять код еще не значит, что мы закончили. Как я уже говорил ранее, из-за атрибута __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 — это следующий фейковый документ для печати.







`;
	
	}

window.print();








Your browser does not support HTML5 video.

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

→ Microsoft.com

© Habrahabr.ru