Let’s talk about some targeted attacks where session management can be targeted to side step multi factor authentication. I’ll be focusing on WordPress, a popular website content management system, that also just happens to handle “sessions” in a unique way which makes this a far more interesting discussion.
At the time of writing, the current release: WordPress 3.5.1 uses the described method to verify logged in status for accounts.
Here’s an example WordPress "session", or authentication cookie:Cookie name: wordpress_81aa6832caa89375bfc354face5f674e
Once you have the equivalent cookie for a WordPress site (which for most WordPress sites is sent over HTTP, allowing it to be sniffed over an insecure wireless network at a coffee shop or conference) you would be able to go to the site’s admin panel and already be logged in able do whatever you want as that user. Oh, and that snazzy multi factor authentication plugin you’re using? It does nothing! Once you have a valid authentication cookie, WordPress will let you access the site as an authenticated user, without needing to go through the multi-factor authentication process.
While I consider it pretty cool to side-step the MFA or authentication steps, I dug a little more in to how WordPress manages these “sessions” and found out a bit more interesting facts. So, let’s get back to the authentication cookie, the first thing we want to do is track down is the name of the cookie, since it’s pretty strange.
This turns out to be pretty straightforward; the cookie names are set in wp-includes/default-constants.php.
It’s a constant that is set in the code and uses nothing at all, or the md5 of the value of $siteurl, which is the site’s domain name, and inadvertently not hard to generate yourself.
Next let’s look over the value.
This is apparently three values separated by |'s. The "admin" username is obvious, and so is that Unix timestamp. That last value 8b03a400e8e416c4eba7a63f6fd616d1 looks like the magic value that makes the whole system work. So let’s see how it is set and how it is used.
Most of the action is in wp-includes/pluggable.php and I’ll start off with a snippet from wp_generate_auth_cookie() that handles setting the cookie’s value.
Here you can see how $cookie is set, we can confirm the assumptions of the username, that timestamp is now evidently the session's expiration date, and now we see that the magic value is an md5 HMAC of user login and expiration time as a string, using a secret $key value that was generated by wp_hash(). So, let's look into that wp_hash()
Here wp_hash() returns a hash using hash_hmac() as well, but it makes sure to use a salt generated by wp_salt() (it gets a little complicated in the code (but it is all still in pluggable.php) but wp_salt() basically returns the site’s secret salt values.)
They provided the wp_hash() function the user login, only 4 characters of the user’s password hash, and the expiration date for the “session”. wp_hash() returns the string from hash_hmac(), but also uses the website’s secret salt values to ensure a confidential string is generated. These salt values are key, as without them it would be trivial to generate your own authentication token.
Now we know how WordPress sites generate a session cookie. Let’s look into how they verify a session is valid, as that is where it gets surprising.
Instead of storing session information in a session table stored on the server, they perform the same calculations on the cookie provided by the visitor to verify if it is valid. The site accepts the browser’s cookie values, then using the provided username + timestamp it calculates the token value using it’s secret salts and sees if the generated token matches the supplied token value.
We can look up the wp_validate_auth_cookie() function in pluggable.php to see for yourself. Spoiler alert: it looks basically the same as the cookie generation function but with comparisons.
You can see $hash is generated in the same way (re-using the same code, and using values form the cookie provided by the browser) and then compared against $hmac (which was pulled earlier from the cookie values) – if they do not match you get some “auth_cookie_bad_hash” action, if they do match you’ll get “auth_cookie_valid”.
The entire session management in WordPress hinges on 2 secret values: The site’s salts, and only 4 characters of the user’s password hash. While this should prevent against brute force attacks, there are still multiple ways this method of authentication/session management can be a abused by an attacker:
- Sessions hijacking (see: Firesheep)
- Lack of session management on the server
- Ability to create sessions without evidence left on the site
This functionality has been in WordPress for a long time (since 2.x versions) and I’m not the first to talk about it. Independent researchers have discussed it and there is a formal CVE regarding the concern of session hijacking with Wordpress sites.
- Just about a year ago, an independent researcher Gennady Kovshenin (@soulseekah) wrote their findings about it in great detail http://codeseekah.com/2012/04/09/why-wordpress-authentication-unique-keys-and-salts-are-important/
- CVE-2012-5868 Session Replay attacks against WordPress (Reported December 2012)
At the time of writing this post, WordPress has yet to addressed this concern. I have discussed it with their security team, and while their response was respectful they informed me they have no immediate plans to enact a fix. In the meantime they recommend using HTTPS for your WordPress login page. (That is, presuming you have HTTPS setup on your WordPress site.)
Let us discuss those attacks:
I will skip going over session hijacking or replay attacks in depth (these have been covered elsewhere plenty of times.) To summarize: If you log in to a WordPress powered website using an insecure connection, someone else on the network could sniff the cookies sent to your browser. They could then use the captured cookies to access the site. Programs like Firesheep have popularized this type of attack.
The lack of session management on the server and the ability to generate valid authentication cookies provides a unique scenario for attackers. They can generate “irrevocable” and undetectable valid session cookies. I say “irrevocable” because there are no documented ways to revoke your site’s authentication cookies. Knowing the code above, you may be able to see how: In order to invalidate a WordPress authentication cookie you have only two options. Change the user’s password, or update the site’s secret salts. Unfortunately, there are no easy ways to generate new secret salts in WordPress core.
How about a hypothetical scenario to make this a little more interesting though? In this scenario we will say an attacker was able to gain access to, or guess the site’s secret salt values. They would then be able to generate their own valid login cookies that expire at arbitrary times. There would be no evidence that the sessions had been generated and no way the site owner would know these valid authentication cookies were created.
Here is a working proof of concept that will iterate through the site’s users and generate valid authentication cookies for each user, and that expire in 2113.
Of course, this is purely the hypothetical scenario where the attacker may have access to your site’s secrets. However, this is true in a post-compromise scenario. If the attackers were able to break into your site, they could leave it untouched and just generate authentication cookies to allow them access to your site later (even after you’ve patched the vulnerability that allowed them access.) This is why any reputable article related to a hacked WordPress site will always inform you to change your site’s secret salts and passwords after a compromise. This step is required to invalidate any session cookies attackers may have created for themselves.
- Even with Multi-Factor Authentication, the authentication step can be bypassed if session ID cookies are not protected.
- Storing session information on the server will allow you to monitor and disable sessions. This is extremely important in the event of a breach.
I hope this post was informative and has made you more aware of the special bond between session management and authentication.