XSS: DOM-based XSS — Основанные на DOM XSS

Источник: «DOM-based XSS»
В этой статье мы рассмотрим межсайтовый скриптинг на основе DOM (DOM XSS), выясним как найти уязвимости DOM XSS.

Что такое межсайтовый скриптинг основанный на DOM

Основанные на DOM XSS уязвимости возникают, когда JavaScript берёт данные из источника, контролируемого злоумышленником, такого как URL-адрес, и передаёт их в приёмник, поддерживающий динамическое выполнение кода, например eval() или innerHTML. Это позволяет злоумышленникам запускать вредоносный JavaScript код, что обычно позволяет им захватывать учётные записи других пользователей.

Для проведения Основанной на DOM XSS атаки необходимо поместить данные в источник, чтобы они распространились на приёмник и вызвали выполнение произвольного JavaScript кода.

Наиболее распространённым источником для DOM XSS является URL-адрес, доступ к которому осуществляется с помощью объекта windows.location. Злоумышленник может создать ссылку для отправки жертвы на уязвимую страницу с полезной нагрузкой в строке запроса и фрагментами URL-адреса. В определённых обстоятельствах, например, при таргетинге на страницу 404 или веб сайт с PHP, полезные данные также могут быть помещены в путь.

Подробное объяснение потока заражения между источниками и приёмниками можно узнать на странице DOM XSS уязвимостей.

Как протестировать межсайтовый скриптинг на основе DOM

Большинство DOM XSS уязвимостей можно быстро и надёжно определить с помощью сканера уязвимостей. Для ручного тестирования межсайтового скриптинга на основе DOM, нужно использовать браузер с инструментами разработчика, например Chrome. Нужно работать с каждым доступным источником по очереди и тестировать каждый по отдельности.

Тестирование HTML-приёмников

Для тестирования DOM XSS в HTML-приёмнике, поместите случайную буквенно-цифровую строку в источник (например, location.search), затем используйте инструменты разработчика для инспектирования HTML и поиска места, где появится ваша строка. Обратите внимание, что параметр браузера Посмотреть исходный код не будет работать для тестирования DOM XSS, поскольку он не учитывает изменения, внесённые в HTML с помощью JavaScript. В инструментах разработчика Chrome вы можете использовать Ctrl+F (или Command+F в MacOS) для поиска вашей строки в DOM.

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

Обратите внимание, что браузеры ведут себя по-разному в отношении URL-кодирования: Chrome, Firefox и Safari будут URL-кодировать URL-адреса location.search и location.hash, в то время как IE11 и Microsoft Edge (до Chromium) не будут URL-кодировать эти источники. Если ваши данные перед обработкой кодируются в URL-строке, то XSS-атака вряд ли сработает.

Тестирование приёмников выполнения JavaScript

Тестирование приёмников выполнения JavaScript для XSS на основе DOM немного сложнее. С этим приёмником ваш ввод не обязательно появляется где-либо в DOM, поэтому вы можете не искать его. Вместо этого нужно использовать отладчик JavaScrip для определения отправляется ли ваш код в приёмник и каким образом.

Для каждого потенциального источника, такого как location, сначала нужно найти случаи в JavaScript коде страницы, где на источник ссылаются. В инструментах разработчика Chrome, можно использовать Ctrl+Shift+F (или Command+Alt+F в MacOS) для поиска исходного кода во всём JavaScript коде страницы.

После того как вы обнаружили, где читается исходный код, можно использовать отладчик JavaScript для добавления точки остановки и проследить, как используется исходное значение. Вы можете обнаружить, что источник присваивается другим переменным. Если это так, вам нужно снова использовать функцию поиска, чтобы отследить эти переменные и посмотреть, передаются ли они в приёмник. Когда найдёте приёмник, которому назначаются данные, полученные из источника, можно использовать отладчик для проверки значения, наведя указатель мыши на переменную, чтобы показать её значение перед отправкой в приёмник. Затем, как и в случае с HTML-приёмниками, нужно уточнить ввод, чтобы увидеть возможно ли провести успешную XSS атаку.

Использование DOM XSS с различными источниками и приёмниками

В принципе, веб-сайт уязвим для межсайтовых сценариев на основе DOM, если существует исполняемый путь, по которому данные могут распространяться от источника к приёмнику. На практике разные источники и приёмники имеют разные свойства поведения, которые могут повлиять на возможность использования и определить какие техники необходимы. Кроме того, сценарии веб-сайта могут выполнять проверку или другую обработку данных, которые необходимо учитывать при попытке использовать уязвимость. Существует множество приёмников, которые относятся к уязвимостям на основе DOM. Далее приведён детальный список.

Приёмник document.write работает с элементами script, поэтому можно использовать простую полезную нагрузку, как показано ниже:

document.write('... <script>alert(document.domain)</script> ...');

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

Приёмник innerHTML не принимает элементы script ни в одном современном браузере, и события svg onload не срабатывают. Это означает, что нужно будет использовать альтернативные элементы, такие как img или iframe. Обработчики событий, такие как onload и onerror, можно использовать вместе с этими элементами. Например:

element.innerHTML='... <img src=1 onerror=alert(document.domain)> ...'

Источники и приёмники в сторонних зависимостях

Современные веб-приложения обычно создаются с использованием ряда сторонних библиотек и фреймворков, которые часто предоставляют дополнительные функции и возможности для разработчиков. Важно помнить, что некоторые из них также являются потенциальными источниками и приёмниками DOM XSS.

DOM XSS в jQuery

Если используется JavaScript библиотека, такая как jQuery, обратите внимание на приёмники, которые могут изменять элементы DOM на странице. Например, функция attr() в jQuery может изменять атрибуты элементов DOM. Если данные считываются из контролируемого пользователем источника, такого как URL-адрес, а затем передаются в функцию attr(), то можно манипулировать отправленным значением для вызова XSS. Например, у нас есть JavaScript код изменяющий атрибут href ссылки, используя данные из URL-адреса:

$(function() {
$('#backLink').attr("href",(new URLSearchParams(window.location.search)).get('returnUrl'));
});

Можно воспользоваться этим, изменив URL-адрес так, чтобы источник location.search содержал вредоносный URL-адрес. После того как JavaScript код страницы применит это вредоносный URL-адрес к ссылке, клик по неё запустит его:

?returnUrl=javascript:alert(document.domain)

Другой потенциальный приёмник, на который следует обратить внимание — селекторная функция jQuery $(), её можно использовать для внедрения вредоносных объектов в DOM.

Раньше jQuery был чрезвычайно популярен, и классическая уязвимость DOM XSS была вызвана тем, что веб-сайты использовали этот селектор в сочетании с источником location.hash для анимации или автоматической прокрутки к определённому элементу на странице. Такое поведение часто реализовывалось с помощью уязвимого обработчика событий hashchange, подобно следующему примеру:

$(window).on('hashchange', function() {
var element = $(location.hash);
element[0].scrollIntoView();
});

Поскольку хэш контролируется пользователем, злоумышленник может использовать его для внедрения вектора XSS в приёмник селектора $(). Более поздние версии jQuery исправили эту конкретную уязвимость, не позволяя внедрять HTML в селектор, когда ввод начинается с символа хэша #. Тем не менее уязвимый код всё ещё можно найти в дикой природе.

Чтобы использовать эту классическую уязвимость, нужно найти способ инициировать событие hashchange без взаимодействия с пользователем. Один из самых простых способов — доставить эксплойт через iframe:

<iframe src="https://vulnerable-website.com#" onload="this.src+='<img src=1 onerror=alert(1)>'">

В этом примере атрибут src указывает на уязвимую страницу с пустым значением хэш. Когда iframe загружается, вектор XSS добавляется к хэшу, вызывая срабатывание события hashchange.

Даже более новые версии jQuery всё ещё могут быть уязвимы через приёмник $(), при условии, что у вас есть полный контроль над его вводом из источника, который не требует префикса #.

DOM XSS в AngularJS

Если используется фреймворк типа AngularJS, становится возможным выполнение JavaScript без угловых скобок или событий. Когда сайт использует для HTML тэга атрибут ng-app, он будет обработан AngularJS. В этом случае AngularJS будет выполнять JavaScript внутри двойных фигурных скобок встречающихся непосредственно в HTML или внутри атрибутов.

DOM XSS в сочетании отражёнными и сохранёнными данными

Некоторые уязвимости основанные исключительно на DOM автономны на одной странице. Если скрипт считывает некоторые данные из URL-адреса и записывает их в опасный приёмник, то уязвимость целиком на стороне клиента.

Однако источники не ограничиваются данными напрямую открывающимися браузерами — они также могут происходить с веб-сайта. Например, веб-сайты часто отображают параметры URL в HTML-ответе сервера. Обычно это связано со стандартным XSS, но также может привести к отражённым DOM XSS уязвимостям.

В отражённой DOM XSS уязвимости сервер обрабатывает данные из запроса и повторяет данные в ответ. Отражённые данные могут быть помещены в строковый литерал JavaScript или элемент данных в DOM, например поле формы. Затем скрипт на странице обрабатывает отражённые данные небезопасным способом, в конечном итоге записывая их в опасный приёмник.

eval('var data = "reflected string"');

Веб-сайты могут хранить данные на сервере и отражать их в другом месте. В хранимой DOM XSS уязвимости сервер получает данные из одного запроса, сохраняет их, а затем включает данные в более поздний ответ. Сценарий в более позднем ответе содержит приёмник, обрабатывающий данные небезопасным способом.

element.innerHTML = comment.author

Какие приёмники могут привести к DOM XSS уязвимостям

Некоторые из основных приёмников приводящих к DOM XSS уязвимостям:

document.write()
document.writeln()
document.domain
element.innerHTML
element.outerHTML
element.insertAdjacentHTML
element.onevent

jQuery функции также являющиеся приёмниками приводящими к DOM XSS уязвимости:

add()
after()
append()
animate()
insertAfter()
insertBefore()
before()
html()
prepend()
replaceAll()
replaceWith()
wrap()
wrapInner()
wrapAll()
has()
constructor()
init()
index()
jQuery.parseHTML()
$.parseHTML()

Как предотвратить DOM XSS уязвимости

В дополнение к общим мерам, описанным на странице уязвимостей основанных на DOM, вам следует избегать динамической записи данных из любого ненадёжного источника в HTML-документ.

Дополнительные материалы

Предыдущая Статья

XSS: Stored XSS — Сохранённые межсайтовые сценарии

Следующая Статья

XSS: Контексты межсайтового скриптинга