XSS: DOM-based 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-документ.