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

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

Что такое хранимый межсайтовый скриптинг?

Хранимый межсайтовый скриптинг (также известный как second-order или persistent XSS) возникает, когда приложение получает данные из недоверенного источника и затем включает эти данные в своих последующих HTTP-ответах в небезопасной форме.

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

POST /post/comment HTTP/1.1
Host: vulnerable-website.com
Content-Length: 100
postId=3&comment=This+post+was+extremely+helpful.&name=Carlos+Montoya&email=carlos%40normal-user.net

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

<p>This post was extremely helpful.</p>

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

<script>/* Bad stuff here... */</script>

В теле HTTP-запроса этот комментарий будет закодирован, например:

comment=%3Cscript%3E%2F*%2BBad%2Bstuff%2Bhere...%2B*%2F%3C%2Fscript%3E

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

<p><script>/* Bad stuff here... */</script></p>

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

Влияние атак сохранённого XSS

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

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

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

Хранимый XSS в различных контекстах

Существуют различные типы сохранённого межсайтового скриптинга. Местоположение данных в ответе приложения определяет тип полезной нагрузки для эксплуатации уязвимости и может влиять на последствия.

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

Как находить и тестировать уязвимости сохранённого XSS

Многие уязвимости сохранённого XSS можно найти с помощью сканера уязвимостей Burp Suite.

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

Entry points into the application's processing include:

  • Параметры или другие данные внутри строки запроса URL и тела запроса.

  • Путь файла в URL.

  • HTTP-заголовки (для которых отражённый XSS обычно невозможно эксплуатировать).

  • Любые каналы (out-of-band routes), по которым злоумышленник может доставить данные в приложение. Конкретные каналы зависят исключительно от реализованного функционала приложения: например, веб-почтовое приложение будет обрабатывать данные из входящих писем; приложение, отображающее ленту Twitter, может обрабатывать данные, содержащиеся в твитах третьих лиц; а новостной агрегатор будет включать данные, поступающие с других веб-сайтов.

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

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

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

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

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

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

После выявления связи между точкой ввода и вывода для каждой такой пары нужно определить контекст появления данных в ответе и протестировать подходящие XSS-пейлоады для этого контекста. На этом этапе методика тестирования аналогична поиску reflected xss.

Last updated