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

Что такое уценка?

Markdown - это простой язык для написания и форматирования контента. Говоря просто, я имею в виду, что нужно изучить небольшой синтаксис, который позволяет писателям писать чистый, но эстетически приятный контент. Его используют повсюду, от Gists и файлов readme на GitHub до самой статьи, которую вы читаете прямо сейчас.

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

Вот пример:

Статьи лучше с визуальными эффектами, особенно щенки с ошейниками. Но за кулисами Medium не хранит веб-страницу HTML и CSS, он хранит файл разметки. За кадром этот хороший мальчик выглядит примерно так:

![The goodest boy](https://images.unsplash.com/the_good_boy.png)

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

Как мы можем получить XSS в уценке?

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

В тестируемом мной веб-приложении я знал, что XSS будет сложной задачей. Это было приложение Angular, которое по умолчанию очищает весь контент, отображаемый на странице. И, основываясь на тестировании API, я знал, что все, что выглядит как HTML или JavaScript, будет удалено до того, как оно будет сохранено в базе данных.

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

Давайте еще раз посмотрим на эту уценку

Другой пример некоторой уценки - ссылка. Его синтаксис идентичен синтаксису изображения, но без префикса "!".

[Click Me](https://www.example.com/)

При обработке Medium это будет выглядеть примерно так:

<a href="https://www.example.com/">Click Me</a>

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

Подвиг!

Первоначальный эксплойт, как оказалось, был довольно простым. Работая в обратном направлении от фрагмента кода привязки выше, мы видим, что у нас есть несколько вариантов. Мы можем либо выйти из атрибута href, и добавить скрипт, который запускается при событии DOM. Или мы можем сделать это проще и разместить код в самом href. Вот для чего мы стремимся:

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

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

[Click Me](javascript:alert('Uh oh...'))

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

Это лучшее, что мы можем сделать?

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

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

Эксплойт, 2 раунд!

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

![The goodest boy](https://images.unsplash.com/the_good_boy.png)

И вот полученный HTML:

<img src="https://images.unsplash.com/the_good_boy.png" alt="The goodest boy">

Конечно, мы можем поместить ту же полезную нагрузку в круглые скобки и получить XSS. По какой-то причине это не сработало. Вот важный момент:

То, как уценка преобразуется в HTML, может отличаться в зависимости от процессора уценки.

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

Если честно, было много проб и ошибок. Попробуйте полезную нагрузку, отправьте ее в API, посмотрите, запустится ли она. Осмотрите результат, отрегулируйте и повторите.

Чтобы сэкономить пару часов на бездельничании, вот лучшие способы внедрить JavaScript в изображение в разметке.

![Uh oh...]("onerror="alert('XSS'))

Это первая полезная нагрузка, которая работает. Мне не удавалось заставить JavaScript выполняться при помещении непосредственно в атрибуты src или alt, но я мог закрыть атрибут src и добавить дополнительные атрибуты. Это превращается в:

<img src="" onerror="alert('XSS') alt="Uh oh...">

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

![Uh oh...](https://www.example.com/image.png"onload="alert('XSS'))

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

Почему это сработало?

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

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

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

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

Спасибо за чтение!
Если вам понравился этот пост, подпишитесь на Twitter и Medium, чтобы получать больше информации. Если у вас есть отзывы или предложения, оставьте их в комментариях ниже, и я постараюсь ответить вам.