PostMessage Vulnerabilities
Вразливості PostMessage
Відправити PostMessage
PostMessage використовує наступну функцію для відправлення повідомлення:
Зауважте, що targetOrigin може бути '*' або URL, наприклад https://company.com. У другому сценарії, повідомлення може бути відправлене лише на цей домен (навіть якщо початковий джерело об'єкта вікна відрізняється). Якщо використовується шаблон, повідомлення можуть бути відправлені на будь-який домен, і будуть відправлені на початкове джерело об'єкта Вікна.
Атака на iframe та шаблон в targetOrigin
Як пояснено в цьому звіті, якщо ви знаходите сторінку, яку можна вставити в iframe (без захисту X-Frame-Header
) і яка надсилає чутливе повідомлення через postMessage, використовуючи шаблон (*), ви можете змінити походження iframe та витікати чутливе повідомлення на домен, яким ви керуєте.
Зауважте, що якщо сторінку можна вставити в iframe, але targetOrigin встановлено на URL, а не на шаблон, цей трюк не працюватиме.
Використання addEventListener
addEventListener
- це функція, яку використовує JS для оголошення функції, яка очікує postMessages
.
Буде використаний код, подібний до наступного:
У цьому випадку першим кроком коду є перевірка походження. Це надзвичайно важливо, особливо якщо сторінка збирається робити чутливі дії з отриманою інформацією (наприклад, змінювати пароль). Якщо не перевіряти походження, атакувальники можуть змусити жертв відправляти довільні дані на ці кінцеві точки та змінювати паролі жертв (у цьому прикладі).
Перелік
Для знаходження прослуховувачів подій на поточній сторінці можна:
Шукати код JS для
window.addEventListener
та$(window).on
(версія JQuery)Виконати у консолі інструментів розробника:
getEventListeners(window)
Перейти до Elements --> Event Listeners у інструментах розробника браузера
Використовувати розширення браузера типу https://github.com/benso-io/posta або https://github.com/fransr/postMessage-tracker. Ці розширення браузера будуть перехоплювати всі повідомлення та показувати їх вам.
Обхід перевірки походження
Атрибут
event.isTrusted
вважається безпечним, оскільки повертаєTrue
лише для подій, які генеруються реальними діями користувача. Хоча його важко обійти, якщо він реалізований правильно, його значення в перевірках безпеки помітне.Використання
indexOf()
для перевірки походження в подіях PostMessage може бути вразливим на обхід. Приклад, що ілюструє цю вразливість:
Метод
search()
зString.prototype.search()
призначений для регулярних виразів, а не для рядків. Передача чого-небудь, крім регулярного виразу, призводить до неявного перетворення на регулярний вираз, що може зробити метод потенційно небезпечним. Це тому, що в регулярних виразах крапка (.) діє як символ підстановки, що дозволяє обійти перевірку з допомогою спеціально створених доменів. Наприклад:
Функція
match()
, подібно доsearch()
, обробляє регулярні вирази. Якщо регулярний вираз побудований неправильно, він може бути вразливим на обхід.Функція
escapeHtml
призначена для санітаризації введених даних шляхом екранування символів. Однак вона не створює новий екранований об'єкт, а перезаписує властивості існуючого об'єкта. Цю поведінку можна використовувати. Зокрема, якщо об'єкт можна маніпулювати так, що його контрольована властивість не визнаєhasOwnProperty
,escapeHtml
не буде працювати як очікувалося. Це показано в прикладах нижче:Очікувана помилка:
Обхід екранування:
У контексті цієї вразливості об'єкт File
особливо вразливий через свою тільки для читання властивість name
. Ця властивість, коли використовується в шаблонах, не санітаризується функцією escapeHtml
, що призводить до потенційних ризиків безпеки.
Властивість
document.domain
в JavaScript може бути встановлена сценарієм для скорочення домену, що дозволяє більш гнучке застосування політики однакового походження в межах одного батьківського домену.
Обхід e.origin == window.origin
e.origin == window.origin
При вбудовуванні веб-сторінки в ізольовану iframe за допомогою %%%%%%, важливо розуміти, що походження iframe буде встановлено на null. Це особливо важливо при роботі з атрибутами пісочниці та їх впливом на безпеку та функціональність.
Вказавши allow-popups
у атрибуті пісочниці, будь-яке вікно спливаючого вікна, відкрите зсередини iframe, успадковує обмеження пісочниці батька. Це означає, що якщо не включено також атрибут allow-popups-to-escape-sandbox
, походження спливаючого вікна також встановлюється на null
, узгоджуючись з походженням iframe.
Отже, коли спливає вікно в таких умовах і з iframe відправляється повідомлення до спливаючого вікна за допомогою postMessage
, як відправник, так і отримувач мають свої походження встановлені на null
. Ця ситуація призводить до сценарію, де e.origin == window.origin
оцінюється як true (null == null
), оскільки як iframe, так і спливаюче вікно мають спільне значення походження null
.
Для отримання додаткової інформації читайте:
pageBypassing SOP with Iframes - 1Обхід e.source
e.source
Можливо перевірити, чи повідомлення надійшло з того ж вікна, в якому скрипт слухає (особливо цікаво для Content Scripts від розширень браузера для перевірки, чи повідомлення було відправлено з тієї ж сторінки):
Ви можете змусити e.source
повідомлення бути нульовим, створивши iframe, який надсилає postMessage та негайно видаляється.
Для отримання додаткової інформації читайте:
pageBypassing SOP with Iframes - 2Обхід заголовка X-Frame
Для виконання цих атак ідеально мати можливість помістити веб-сторінку жертви всередині iframe
. Але деякі заголовки, такі як X-Frame-Header
, можуть запобігти цьому поведінці.
У таких сценаріях ви все ще можете використовувати менш приховану атаку. Ви можете відкрити нову вкладку на вразливому веб-застосунку та спілкуватися з ним:
Викрадення повідомлення, відправленого дитині, блокуючи головну сторінку
На наступній сторінці ви можете побачити, як ви можете викрасти чутливі дані postmessage, відправлені до дитячого iframe, блокуючи головну сторінку перед відправленням даних та зловживаючи XSS в дитині, щоб витікати дані до їх отримання:
pageBlocking main page to steal postmessageВикрадення повідомлення шляхом зміни місцезнаходження iframe
Якщо ви можете вбудувати веб-сторінку без заголовка X-Frame, яка містить інший iframe, ви можете змінити місцезнаходження цього дитячого iframe, тому якщо він отримує postmessage, відправлене за допомогою шаблону, зловмисник може змінити походження цього iframe на сторінку, контрольовану ним і викрасти повідомлення:
pageSteal postmessage modifying iframe locationpostMessage до забруднення прототипу та/або XSS
У сценаріях, де дані, відправлені через postMessage
, виконуються JS, ви можете вбудувати сторінку та експлуатувати забруднення прототипу/XSS, відправляючи експлойт через postMessage
.
Декілька дуже добре пояснених XSS через postMessage
можна знайти за посиланням https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html
Приклад експлойту для зловживання забрудненням прототипу, а потім XSS через postMessage
до iframe
:
Для додаткової інформації:
Посилання на сторінку про забруднення прототипу
Посилання на сторінку про XSS
Посилання на сторінку про забруднення прототипу на клієнтській стороні до XSS
Посилання
Для практики: https://github.com/yavolo/eventlistener-xss-recon
Last updated