CWE: CWE-384: Session Fixation, CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
Affected runtime: .NET Core (latest)
Affected source code: CookieParser.cs
The System.Net.HttpListener cookie parser is vulnerable to two distinct but related attacks that involve manipulating cookies in insecure ways. Although cookies marked as HttpOnly are designed to be inaccessible to JavaScript, an attacker with XSS capabilities can set or overwrite protected cookies, potentially leading to data exposure in some cases.
-
Cookie Spoofing
An attacker can set or overwrite protected cookies, including session identifiers or authentication tokens. This can lead to session fixation, account impersonation, or persistent access, as outlined in CWE-384 and other session management vulnerabilities. -
Cookie Exposure
When the server includes any non-protected cookie in its responses (e.g., by writing it into an HTML response), an attacker can craft a special cookie that causes theHttpOnlyprotected cookie value to be leaked. This exposure could allow an attacker to gain unauthorized access to sensitive session information, as described in CWE-200.
Although HttpListener is leveraged by various open-source HTTP server frameworks, such as Kestrel, it remains a widely used component in .NET applications, particularly for lightweight HTTP server implementations. It is still cross-platform, supported on Windows, Linux, and macOS as part of the .NET runtime. It has not been marked as deprecated, and this makes it a viable option for projects where simplicity or minimal configuration is required.
The cookie parsing logic in .NET Core does not strictly follow RFC 6265 (HTTP State Management Mechanism), which specifies restrictions on characters allowed in cookie names and values.
According to RFC, cookie names must not contain the comma character (,), as it is a reserved delimiter used to separate multiple cookies in the Cookie header. However, the .NET Core cookie parser incorrectly ignores commas in cookie names and allows an attacker to craft malicious cookies that are misinterpreted by the server.
RFC also explicitly prohibits the inclusion of the double quote (") character in cookie values. Despite this, the .NET Core parser incorrectly treats the double quote as if the cookie value is encapsulated in quotes, ignoring subsequent cookie delimiters. This leads to potential vulnerabilities, where the cookie value may be misinterpreted, and could be used to bypass security controls.
Consider the backend setting a cookie as follows:
Set-Cookie: session_id=secure; Path=/; HttpOnly
An attacker, utilizing XSS, can inject a malicious cookie:
document.cookie = ',session_id=spoofed; Path=/';The resulting Cookie header will be:
Cookie: session_id=secure; ,session_id=spoofed
As a consequence, the backend will parse the cookies as:
context.Request.Cookies["session_id"].Value == "spoofed"This behavior bypasses the intended protection of the HttpOnly flag, allowing the attacker to overwrite sensitive cookies, including session identifiers, effectively compromising the session.
Assume the backend returns a non-protected cookie, such as captcha_id, in an HTML response, while also having a protected HttpOnly cookie, session_id.
The attacker, using XSS, injects a crafted cookie:
document.cookie = 'captcha_id="leaked; Path=/';Then, the attacker forces the backend to set the session_id cookie with HttpOnly flag. The Cookie header becomes:
Cookie: captcha_id="leaked; session_id=secure
When the captcha_id is rendered in the HTML response, it will contain the value of session_id:
leaked; session_id=secure
This results in the unintended exposure of the session_id cookie, potentially leaking sensitive session data to the attacker.
I've provided two files:
- Program.cs
- cookie.csproj
Steps to reproduce:
- run with
dotnet runand open http://localhost:5000/
- use the form to set the
session_idcookie (via backend withHttpOnlyflag) - observe the correct value in response from the server
- click "set spoof cookie" to inject a spoofing cookie
- observe the
session_idis overwritten withspoofedeven though theHttpOnlybeing set - click "clear spoof cookie" to delete the spoofing cookie
- click "delete cookie" to clear the
session_idcookie
- now click "set captcha cookie" to inject a crafted
captcha_idcookie - use the form to set the
session_idcookie (via backend withHttpOnlyflag) - observe the
captcha_idnow contains the value ofsession_idcookie
Sanitize and strictly validate cookie names and values against RFC 6265 in the parsing logic. Cookie names and values containing illegal characters should be rejected.