“Never roll your own crypto.”

In-house crypto is often a goldmine of cryptographic errors and vulnerabilities. In this post, I’ll describe one of the glaring errors discovered in an online customer support and help desk solution we were considering for use in Praetorian’s cloud-based password cracking service, Project Mars. Hopefully, this can serve as a warning to anyone thinking about writing his or her own crypto libraries.

––
Disclaimer: The affected party was notified of the following vulnerabilities in July of 2013, however, I will avoid mentioning them by name as they have yet to fix one of the bugs.

––

The pair of vulnerabilities I will be discussing involve the concept of MAC, or Message Authentication Codes. To briefly summarize the concept, a MAC is a short piece of data used to validate the integrity and authenticity of a message. There are many different algorithms for producing a MAC, some more secure than others, but the gist of the process is a function that takes data and a key as input and returns a small tag as output. This tag can be used to verify that data was not tampered with during transit. Tags are used by many services as a means of authenticating users (often for API calls) and they are often generated insecurely or improperly.

Learn more: I highly recommend Stanford’s online cryptography courses taught by professor Dan Boneh. Learn more about MAC in lecture 22 of his Introduction to Cryptography video series.

Using MAC for SSO Authentication

In this post, I examine a system in which a MAC is used to authenticate a user for Single-Sign-On. This system allows a website to authenticate its users to a third-party service without forcing them to create a new account for this service. For the sake of clarity, we’ll call the website Praetorian and the third-party IntegrityDesk. In order to authenticate a user to IntegrityDesk, Praetorian and IntegrityDesk must agree on a secret_key to be used in all signature calculations. After creating a shared secret, Praetorian can craft the following token to authenticate a user:

token = MD5(username + email + secret_key)

IntegrityDesk can then validate this token by computing the same hash using the shared secret_key value. After IntegrityDesk has validated the hash, it considers the user authenticated for the service.

This method of authentication would usually be secure since an attacker cannot possibly generate the token without knowing the secret_key.

IntegrityDesk SSO Authentication Exchange

authentication flow

Examples of MAC Authentication Attacks

Unfortunately, there are two simple attacks against this MAC. The first of our two attacks is classified as a replay attack. If an attacker is ever able to capture a user’s token – through Man-in-the-Middling traffic – they will be able to authenticate as that user by merely replaying the authentication request to /auth. A secure MAC should incorporate some element of time or a nonce that can be rejected after a sufficient period of inactivity. By adding a time / nonce parameter, IntegrityDesk can help protect users against replay attacks.

In addition to the replay attack, there exists a clever attack that abuses the string used to create the token. The following short example demonstrates this attack.

Imagine an admin user logged in to Praetorian’s site with the following username and email:

username = ‘sudo’
email = ‘administator@example.com’

Their token will be equal to the MD5 hash of the concatenation of their username, email, and Praetorian’s secret key:

token = MD5(‘sudoadministrator@example.com’ + secret_key)

Now imagine a new user who knows of this admin account and is able to choose their username and email with the restriction that it must differ from the admin account. A malicious user could choose the following {username, email} pair to receive a token from Praetorian.

username = ‘sudoadminis’
email = ‘trator@example.com’
token = MD5(‘sudoadministrator@example.com’ + secret_key)

As you can see, this construction will provide the exact same token as the admin user, while using a different username and email. To complete the attack, our malicious user can just take their token and send a request to IntegrityDesk:

integrity desk url

IntegrityDesk can verify that the hash of sudo and administrator@example.com is equivalent to the provided token and will happily authenticate our malicious user with admin status.

Use a Secure Message Integrity Algorithm

As you can see, using MAC for authentication is often a tricky business with many potential vulnerabilities. The attacks described above could be remedied by using a secure message integrity algorithm (such as HMAC), running integrity checks on the entire message instead of individual components, and incorporating a nonce / timestamp into the message.

token = HMAC(secret_key, ‘username=sudo&email=administrator@example.com&nonce=554134&timestamp=1406130479’)