This commit is contained in:
carlospolop 2025-09-07 23:56:50 +02:00
parent 2467c484ac
commit 4cf8e215f8
2 changed files with 70 additions and 0 deletions

View File

@ -215,6 +215,15 @@ Hunting/IOCs
- AMSI tampering via [System.Management.Automation.AmsiUtils]::amsiInitFailed.
- Long-running business threads ending with links hosted under trusted PaaS domains.
## Windows files to steal NTLM hashes
Check the page about **places to steal NTLM creds**:
{{#ref}}
../../windows-hardening/ntlm/places-to-steal-ntlm-creds.md
{{#endref}}
## References
- [Check Point Research ZipLine Campaign: A Sophisticated Phishing Attack Targeting US Companies](https://research.checkpoint.com/2025/zipline-phishing-campaign/)

View File

@ -107,6 +107,65 @@ Or in PHP it was possible to add **other characters at the beginning** of the co
<figure><img src="../../images/image (7) (1) (1) (1) (1).png" alt="" width="373"><figcaption></figcaption></figure>
#### Unicode whitespace cookie-name smuggling (prefix forgery)
Abuse discrepancies between browser and server parsing by prepending a Unicode whitespace code point to the cookie name. The browser wont 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.
- PoC from a subdomain that can set parent-domain cookies:
```js
document.cookie = `${String.fromCodePoint(0x2000)}__Host-name=injected; Domain=.example.com; Path=/;`;
```
- Typical backend behavior that enables the issue:
- Frameworks that trim/normalize cookie keys. In Django, Pythons `str.strip()` removes a wide range of Unicode whitespace code points, causing the name to normalize to `__Host-name`.
- Commonly trimmed code points include: U+0085 (NEL, 133), U+00A0 (NBSP, 160), U+1680 (5760), U+2000U+200A (81928202), U+2028 (8232), U+2029 (8233), U+202F (8239), U+205F (8287), U+3000 (12288).
- Many frameworks resolve duplicate cookie names as “last wins”, so the attacker-controlled normalized cookie value overwrites the legitimate one.
- Browser differences matter:
- 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.
- 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.
- On-the-wire vs server view example (U+2000 present in name):
```
Cookie: __Host-name=Real;  __Host-name=<img src=x onerror=alert(1)>;
```
Many backends split/parse and then trim, resulting in the normalized `__Host-name` taking the attackers value.
#### Legacy `$Version=1` cookie splitting on Java backends (prefix bypass)
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.
- PoC forcing legacy parsing:
```js
document.cookie = `$Version=1,__Host-name=injected; Path=/somethingreallylong/; Domain=.example.com;`;
```
- Why it works:
- 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.
- Where to try: Tomcat, Jetty, Undertow, or frameworks that still honor RFC 2109/2965 attributes. Combine with duplicate-name overwrite semantics.
#### Duplicate-name last-wins overwrite primitive
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.
#### Detection and tooling
Use Burp Suite to probe for these conditions:
- 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.
- Send `$Version=1` first in the Cookie header and check if the backend performs legacy splitting/normalization.
- Observe duplicate-name resolution (first vs last wins) by injecting two cookies that normalize to the same name.
- Burp Custom Action to automate this: [CookiePrefixBypass.bambda](https://github.com/PortSwigger/bambdas/blob/main/CustomAction/CookiePrefixBypass.bambda)
> Tip: These techniques exploit RFC 6265s octet-vs-string gap: browsers send bytes; servers decode and may normalize/trim. Mismatches in decoding and normalization are the core of the bypass.
## Cookies Attacks
If a custom cookie contains sensitive data check it (specially if you are playing a CTF), as it might be vulnerable.
@ -339,6 +398,8 @@ There should be a pattern (with the size of a used block). So, knowing how are a
- [https://seclists.org/webappsec/2006/q2/181](https://seclists.org/webappsec/2006/q2/181)
- [https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it](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/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
- [Cookie Chaos: How to bypass __Host and __Secure cookie prefixes](https://portswigger.net/research/cookie-chaos-how-to-bypass-host-and-secure-cookie-prefixes)
- [Burp Custom Action CookiePrefixBypass.bambda](https://github.com/PortSwigger/bambdas/blob/main/CustomAction/CookiePrefixBypass.bambda)
{{#include ../../banners/hacktricks-training.md}}