Недавно я наткнулся на веб-приложение, в котором я смог использовать уязвимость межсайтового скриптинга (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, чтобы получать больше информации. Если у вас есть отзывы или предложения, оставьте их в комментариях ниже, и я постараюсь ответить вам.