DOM-based XSS

В этом разделе мы опишем, что такое уязвимости DOM-based XSS, расскажем, как находить такие уязвимости, и обсудим техники эксплуатации DOM XSS с разными источниками (sources) и приёмниками данных (sinks).

Что такое DOM-based XSS?

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

Чтобы провести атаку DOM-based XSS, необходимо поместить данные в источник так, чтобы они попали в приёмник и привели к выполнению произвольного JavaScript-кода.

Самый распространённый источник для DOM XSS — это URL, к которому обычно обращаются через объект window.location. Атакующий может сформировать ссылку, отправляющую жертву на уязвимую страницу с полезной нагрузкой в query-string или фрагменте URL. В некоторых случаях (например, при обращении к странице 404 или при работе с PHP) полезная нагрузка может размещаться и в пути URL.

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

Как тестировать DOM-based XSS

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

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

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

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

Тестирование приёмников, исполняющих JavaScript-код

Тестирование приёмников, исполняющих JavaScript-код, на уязвимости DOM-based XSS значительно сложнее. В таких случаях ваш ввод не обязательно появляется в DOM, поэтому поискать его обычным образом невозможно. Вместо этого нужно использовать отладчик JavaScript, чтобы понять, достигает ли ваш ввод нужного приёмника (sink) и каким образом.

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

Когда вы определили, где источник используется, поставьте точку останова (breakpoint) с помощью JavaScript-отладчика и отслеживайте, как переменная с данными от источника применяется в коде. Часто бывает, что эти данные присваиваются другим переменным. В таком случае повторно используйте поиск по коду, чтобы найти, где эти переменные фигурируют дальше, и выясните, не попадают ли они в опасный приёмник (sink).

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

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

Поиск и эксплуатация DOM XSS в реальных условиях часто требует ручного анализа большого количества сложного и минифицированного кода. Браузер Burp Suite предлагает расширение DOM Invader, которое берет на себя большую часть работы по выявлению и эксплуатации DOM XSS.

Эксплуатация DOM XSS с разными источниками и приёмниками

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

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

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

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

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

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

DOM XSS в jQuery

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

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

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

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

Поскольку hash контролируется пользователем, атакующий может использовать это для внедрения XSS-вектора в селектор $() (sink). В более новых версиях jQuery эта конкретная уязвимость была исправлена за счет предотвращения инъекции HTML в селектор, когда ввод начинается с символа решетки (#). Однако уязвимый код все еще можно встретить в дикой природе.

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

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

Note

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

DOM XSS в AngularJS

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

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

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

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

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

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

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

Ниже приведены некоторые из основных sinks, которые могут приводить к DOM XSS уязвимостям:

Следующие функции jQuery также являются sinks, которые могут приводить к DOM XSS уязвимостям:

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

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

Last updated