CSS Injection
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
CSS селектори створені для відповідності значенням атрибутів name
та value
елемента input
. Якщо атрибут значення елемента введення починається з певного символу, завантажується попередньо визначений зовнішній ресурс:
Однак цей підхід стикається з обмеженням при роботі з прихованими елементами введення (type="hidden"
), оскільки приховані елементи не завантажують фони.
Щоб обійти це обмеження, ви можете націлитися на наступний елемент-сibling, використовуючи комбінацію загального sibling ~
. Правило CSS тоді застосовується до всіх sibling, що йдуть після прихованого елемента введення, змушуючи фонове зображення завантажуватися:
A practical example of exploiting this technique is detailed in the provided code snippet. You can view it here.
For the CSS Injection technique to be effective, certain conditions must be met:
Payload Length: Вектор CSS-ін'єкції повинен підтримувати достатньо довгі корисні навантаження для розміщення створених селекторів.
CSS Re-evaluation: Ви повинні мати можливість оформити сторінку, що необхідно для виклику повторної оцінки CSS з новоствореними корисними навантаженнями.
External Resources: Техніка передбачає можливість використання зовнішньо розміщених зображень. Це може бути обмежено політикою безпеки контенту (CSP) сайту.
As explained in this post, it's possible to combine the selectors :has
and :not
to identify content even from blind elements. This is very useful when you have no idea what is inside the web page loading the CSS injection.
It's also possible to use those selectors to extract information from several block of the same type like in:
Об'єднуючи це з наступною технікою @import, можливо ексфільтрувати багато інформації за допомогою CSS-ін'єкції з сліпих сторінок з blind-css-exfiltration.
Попередня техніка має деякі недоліки, перевірте вимоги. Вам потрібно або надіслати кілька посилань жертві, або ви повинні мати можливість вставити в iframe сторінку, вразливу до CSS-ін'єкції.
Однак є ще одна хитра техніка, яка використовує CSS @import
для покращення якості техніки.
Це вперше показав Pepe Vila і це працює так:
Замість того, щоб завантажувати одну й ту ж сторінку знову і знову з десятками різних корисних навантажень щоразу (як у попередньому випадку), ми будемо завантажувати сторінку лише один раз і лише з імпортом на сервер зловмисника (це корисне навантаження, яке потрібно надіслати жертві):
Імпорт буде отримувати деякий CSS скрипт від атакуючих, і браузер його завантажить.
Перша частина CSS скрипту, яку надішле атакуючий, буде іншим @import
на сервер атакуючих знову.
Сервер атакуючих поки не відповість на цей запит, оскільки ми хочемо витікати деякі символи, а потім відповісти на цей імпорт з корисним навантаженням, щоб витікати наступні.
Друга і більша частина корисного навантаження буде корисним навантаженням для витоку селектора атрибутів
Це надішле на сервер атакуючих перший символ секрету та останній.
Як тільки сервер атакуючих отримає перший і останній символ секрету, він відповість на імпорт, запитаний на кроці 2.
Відповідь буде точно такою ж, як кроки 2, 3 і 4, але цього разу він спробує знайти другий символ секрету, а потім передостанній.
Атакуючий продовжить цей цикл, поки не зможе повністю витікати секрет.
Ви можете знайти оригінальний код Пепе Віли для експлуатації цього тут або ви можете знайти майже той же код, але з коментарями тут.
Скрипт спробує виявити 2 символи щоразу (з початку і з кінця), оскільки селектор атрибутів дозволяє робити такі речі:
Це дозволяє скрипту швидше витікати секрет.
Іноді скрипт неправильно визначає, що префікс + суфікс, що було виявлено, вже є повним флагом і продовжить рухатися вперед (в префіксі) і назад (в суфіксі), і в якийсь момент він зависне. Не хвилюйтеся, просто перевірте вихідні дані, тому що ви можете побачити флаг там.
Інші способи доступу до частин DOM за допомогою CSS селекторів:
.class-to-search:nth-child(2)
: Це буде шукати другий елемент з класом "class-to-search" в DOM.
:empty
селектор: Використовується, наприклад, в цьому описі:
Посилання: CSS на основі атаки: Зловживання unicode-range з @font-face , Помилка на основі XS-Search PoC від @terjanq
Загальна мета полягає в тому, щоб використовувати власний шрифт з контрольованої точки доступу і забезпечити, щоб текст (в даному випадку, 'A') відображався цим шрифтом лише в тому випадку, якщо вказаний ресурс (favicon.ico
) не може бути завантажений.
Використання Користувацького Шрифту:
Користувацький шрифт визначається за допомогою правила @font-face
у тегу <style>
в секції <head>
.
Шрифт називається poc
і завантажується з зовнішнього кінцевого пункту (http://attacker.com/?leak
).
Властивість unicode-range
встановлена на U+0041
, націлюючись на конкретний символ Юнікоду 'A'.
Елемент Object з Резервним Текстом:
Елемент <object>
з id="poc0"
створюється в секції <body>
. Цей елемент намагається завантажити ресурс з http://192.168.0.1/favicon.ico
.
font-family
для цього елемента встановлено на 'poc'
, як визначено в секції <style>
.
Якщо ресурс (favicon.ico
) не вдається завантажити, резервний контент (літера 'A') всередині тегу <object>
відображається.
Резервний контент ('A') буде відображено за допомогою користувацького шрифту poc
, якщо зовнішній ресурс не може бути завантажено.
Псевдоклас :target
використовується для вибору елемента, на який націлений фрагмент URL, як зазначено в специфікації CSS Selectors Level 4. Важливо розуміти, що ::target-text
не відповідає жодним елементам, якщо текст не націлений явно фрагментом.
Проблема безпеки виникає, коли зловмисники експлуатують функцію Scroll-to-text фрагмента, що дозволяє їм підтвердити наявність конкретного тексту на веб-сторінці, завантажуючи ресурс з їхнього сервера через HTML-ін'єкцію. Метод полягає в ін'єкції CSS правила, як це:
У таких сценаріях, якщо текст "Administrator" присутній на сторінці, ресурс target.png
запитується з сервера, що вказує на присутність тексту. Приклад цієї атаки можна виконати через спеціально підготовлене URL, яке вбудовує ін'єкційний CSS разом з фрагментом Scroll-to-text:
Тут атака маніпулює HTML-ін'єкцією для передачі CSS-коду, націлюючись на конкретний текст "Administrator" через фрагмент Scroll-to-text (#:~:text=Administrator
). Якщо текст знайдено, вказаний ресурс завантажується, ненавмисно сигналізуючи про свою присутність атакуючому.
Для пом'якшення слід звернути увагу на такі пункти:
Обмежене відповідність STTF: Фрагмент Scroll-to-text (STTF) призначений для відповідності лише словам або реченням, тим самим обмежуючи його здатність витікати довільні секрети або токени.
Обмеження до верхнього рівня контекстів перегляду: STTF працює виключно в контекстах верхнього рівня перегляду і не функціонує в iframe, що робить будь-яку спробу експлуатації більш помітною для користувача.
Необхідність активації користувачем: STTF вимагає жесту активації користувача для роботи, що означає, що експлуатації можливі лише через ініційовану користувачем навігацію. Ця вимога значно зменшує ризик автоматизації атак без взаємодії з користувачем. Проте автор блогу вказує на специфічні умови та обходи (наприклад, соціальна інженерія, взаємодія з поширеними розширеннями браузера), які можуть полегшити автоматизацію атаки.
Обізнаність про ці механізми та потенційні вразливості є ключовою для підтримки веб-безпеки та захисту від таких експлуатаційних тактик.
Для отримання додаткової інформації перегляньте оригінальний звіт: https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/
Ви можете перевірити експлойт, що використовує цю техніку для CTF тут.
Ви можете вказати зовнішні шрифти для конкретних значень unicode, які будуть збиратися лише якщо ці значення unicode присутні на сторінці. Наприклад:
When you access this page, Chrome and Firefox fetch "?A" and "?B" because text node of sensitive-information contains "A" and "B" characters. But Chrome and Firefox do not fetch "?C" because it does not contain "C". This means that we have been able to read "A" and "B".
Reference: Викрадення даних у чудовому стилі – тобто як використати CSS для атак на вебдодаток
The technique described involves extracting text from a node by exploiting font ligatures and monitoring changes in width. The process involves several steps:
Creation of Custom Fonts:
SVG fonts are crafted with glyphs having a horiz-adv-x
attribute, which sets a large width for a glyph representing a two-character sequence.
Example SVG glyph: <glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>
, where "XY" denotes a two-character sequence.
These fonts are then converted to woff format using fontforge.
Detection of Width Changes:
CSS is used to ensure that text does not wrap (white-space: nowrap
) and to customize the scrollbar style.
The appearance of a horizontal scrollbar, styled distinctly, acts as an indicator (oracle) that a specific ligature, and hence a specific character sequence, is present in the text.
The CSS involved:
Exploit Process:
Step 1: Fonts are created for pairs of characters with substantial width.
Step 2: A scrollbar-based trick is employed to detect when the large width glyph (ligature for a character pair) is rendered, indicating the presence of the character sequence.
Step 3: Upon detecting a ligature, new glyphs representing three-character sequences are generated, incorporating the detected pair and adding a preceding or succeeding character.
Step 4: Detection of the three-character ligature is carried out.
Step 5: The process repeats, progressively revealing the entire text.
Optimization:
The current initialization method using <meta refresh=...
is not optimal.
A more efficient approach could involve the CSS @import
trick, enhancing the exploit's performance.
Reference: PoC using Comic Sans by @Cgvwzq & @Terjanq
This trick was released in this Slackers thread. The charset used in a text node can be leaked using the default fonts installed in the browser: no external -or custom- fonts are needed.
The concept revolves around utilizing an animation to incrementally expand a div
's width, allowing one character at a time to transition from the 'suffix' part of the text to the 'prefix' part. This process effectively splits the text into two sections:
Prefix: The initial line.
Suffix: The subsequent line(s).
The transition stages of the characters would appear as follows:
C ADB
CA DB
CAD B
CADB
During this transition, the unicode-range trick is employed to identify each new character as it joins the prefix. This is achieved by switching the font to Comic Sans, which is notably taller than the default font, consequently triggering a vertical scrollbar. This scrollbar's appearance indirectly reveals the presence of a new character in the prefix.
Although this method allows the detection of unique characters as they appear, it does not specify which character is repeated, only that a repetition has occurred.
Basically, the unicode-range is used to detect a char, but as we don't want to load an external font, we need to find another way. When the char is found, it's given the pre-installed Comic Sans font, which makes the char bigger and triggers a scroll bar which will leak the found char.
Check the code extracted from the PoC:
Reference: Це згадується як невдале рішення в цьому звіті
Цей випадок дуже схожий на попередній, однак у цьому випадку мета зробити конкретні символи більшими за інші, щоб приховати щось на кшталт кнопки, щоб її не натиснув бот, або зображення, яке не буде завантажено. Таким чином, ми могли б виміряти дію (або відсутність дії) і дізнатися, чи присутній конкретний символ у тексті.
Reference: Це згадується як невдале рішення в цьому звіті
У цьому випадку ми могли б спробувати витікати, чи є символ у тексті, завантажуючи фальшивий шрифт з того ж походження:
Якщо є збіг, шрифт буде завантажено з /static/bootstrap.min.css?q=1
. Хоча він не завантажиться успішно, браузер повинен його кешувати, і навіть якщо кешу немає, існує механізм 304 not modified, тому відповідь повинна бути швидшою за інші.
Однак, якщо різниця в часі між кешованою відповіддю та некешованою не є достатньо великою, це не буде корисно. Наприклад, автор зазначив: Однак, після тестування, я виявив, що перша проблема полягає в тому, що швидкість не дуже відрізняється, а друга проблема в тому, що бот використовує прапорець disk-cache-size=1
, що дійсно продумано.
Посилання: Це згадується як невдале рішення в цьому звіті
У цьому випадку ви можете вказати CSS для завантаження сотень фальшивих шрифтів з того ж походження, коли відбувається збіг. Таким чином, ви можете виміряти час, який це займає, і дізнатися, чи з'являється символ чи ні, за допомогою чогось на кшталт:
А код бота виглядає так:
Отже, якщо шрифт не збігається, час відповіді при відвідуванні бота очікується приблизно 30 секунд. Однак, якщо є збіг шрифтів, буде надіслано кілька запитів для отримання шрифту, що призведе до постійної активності в мережі. Як наслідок, знадобиться більше часу для задоволення умови зупинки та отримання відповіді. Тому час відповіді можна використовувати як індикатор для визначення, чи є збіг шрифтів.
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)