The poor design decisions of Entrust IdentityGuard soft tokens
It’s not uncommon to see software tokens used for MFA (Multi-factor authentication). The most common of these are probably TOTP based solutions, such as Google Authenticator (or any of the other applications implementing the protocol). While they have specific weaknesses that make them inappropriate for high-value targets (namely their ability to be phished from users), they’re generally considered robust.
However, there’s a dark underbelly of alternative TOTP implementations that aren’t quite the same. When you sign up for GitHub’s TOTP, you are given a QR code which you can import into almost any TOTP compatible implementation you choose, even something like the command line oathtool
. When you instead use something like Entrust’s software token (IdentityGuard), you’re forced to use their application. It’s similar enough to TOTP that you might think you could trivially switch back to a standard application, but several hurdles prevent you from doing so. In my experience, people tend to consider it “good enough”, like a more vanilla TOTP implementation, without looking into the details.
This post is going to explore the specific design decisions that Entrust has taken with their IdentityGuard soft tokens, and how they impact the security of the solution. The application, called “Entrust IdentityGuard Mobile” (or “Entrust ST”), can be found on both Google Play and the iOS App Store, as well as a desktop version.
If you’re just interested in a summary, scroll down to the bottom of the post for a short list of the possible attacks you can perform and the GitHub page the code is located on.
Standard Enrollment
The way you enroll a new token with most TOTP implementations is fairly standard. You access the applications MFA configuration area, attempt to add a new token, and are presented with a QR code to scan. You can scan the QR code with your mobile phone (or otherwise decode the data within), which adds the token to your device. Some applications may require you to enter the generated TOTP token for verification and to verify time-synchronization, but this isn’t mandatory.
The reason this works is that all of the data your phone needs to generate a token is contained within the QR code (and the current time – hence why these are Time-based One-Time Password). The following example QR code is taken from GitHub:
The QR code can be decoded online using tools such as https://zxing.org/w/decode. When decoded, the data is:
otpauth://totp/GitHub:ss23?secret=fswbcdwjeda35nn4&issuer=GitHub
Right away, we can see a lot of generic information. The URI handler is “otpauth”, with a path specifier of “totp”, and a “secret” parameter. When I scan this QR code to my phone, I can see the information is used to configure the tokens I’ll receive:
We can confirm that all is well by generating a QR code on our computer locally, with the default TOTP settings dialed in:
ss23@crisp $ oathtool -b 'fswbcdwjeda35nn4' --totp=sha1
934210
This validates our previous understanding of the tokens: all the information required to generate tokens is contained within the QR code. This has some obvious security consequences as part of the enrollment process.
A TOTP enrollment QR code must never be shared with anyone who is not setting up the token. If anyone obtains the QR code, even if they obtain it years in the future, they will be able to generate tokens and bypass the MFA requirement. This very specific requirement and obvious failure condition lead most TOTP implementors to take specific steps to protect the QR code. This includes things like never emailing out the QR code, generating the QR code in HTML instead of an image (as it might be cached), and preventing anyone from ever viewing the QR code after the enrollment is completed.
Entrust IdentityGuard Enrollment
If you would like to follow along, you can sign up for an IntelliTrust trial, which will allow you to enroll IdentityGuard soft tokens, at https://entrust.us.trustedauth.com/#/signup
To begin analyzing the Entrust enrollment process, we’ll need a QR code. Thankfully, searching Google Images for something like “entrust identityguard qr code” gives us useful results like https://www.umc.edu/DIS/files/Entrust%20Files/ios-soft-token-via-qr-code-entrust-identityguard-registration-tip-sheet.pdf.
Once we extract the QR code from that PDF and decode it, we see the following data:
igmobileotp://?action=secactivate&enc=VRUq6IoLWQRCMRITZEHtHUSWJiPwgu%2FN1BFyUHE5kxuHIEYoE3zmNTrAHeeUM5S3gzCnTy%2F%2Bdnbu%2FsjjQW%2BNEISx8C4ra8rLpxOl8E8w4KXHgjeBRgdvSzl%2BbzX5RYRrQlWgK8hsBT4pQYE0eFgW2TmRbzXu1Mu7XjKDcwsJLew32jQC2qyPLP8hljnv2rHwwsMfhQwgJUJYfctwLWWEDUFukEckaZ4O&v=1&mac=mhVL8BWKaishMa5%2B
Immediately we can see this is drastically different from the process we dealt with for standard TOTP tokens. Of note is the different URL handler, which indicates this QR code is only able to be used with the IdentityGuard application, and the enc and mac parameters, indicating the data contained within is encrypted somehow. This is confirmed by viewing the enrollment PDF again, which contains a password next to the QR code.
To aid in further investigation, I’m going to switch to using an example enrollment email from the IntelliTrust trial, which allows me to choose which activation methods can be used for the token. By default, all methods are selected, which results in an email looking like this:
This email indicates there are three ways to enroll a token: online enrollment using a URL, offline enrollment using a QR code, or offline enrollment using an address, serial, and activation code.
From here we’re going to need to use some reverse engineering and brute-force to determine how the enrollment takes place. I won’t go into the details of how I performed this here, but the result of this work can be found on my GitHub: https://github.com/ss23/entrust-identityguard-tools/.
Entrust IdentityGuard QR Codes
The QR code data contains a salt/nonce, which when combined with the password using PBKDF2-HMAC-SHA256, generates an AES key to decrypt the data:
ss23@crisp $ ./decode-qr-uri.py 'igmobileotp://?action=secactivate&enc=UuMXVIqUa8RglsnNYY7eUb9hHJX7WZMO0dq95remibffJhkjhmOYjNezwh2%2Bx7pEqy4tNPIfsqg2Hzwx0a78fbeox0i6crZY0dO4PQfe3XUSBx%2B8cw79TmgKybUo2kfX385sSif8v5rP46uaaXk3jV3xrarfjDNRU7%2FJ0YZ64v65GMlOzoFI5Kz64vnKFwdY9xqCsBF110Q%3D&v=1&mac=9mRPt5k%2FBAM56bR2' 76916364
{"sn":"18924-27533","ac":"0186-3302-4398-6152","policy":"{\"allowUnsecured\":\"false\"}","regurl":"ss23.us.trustedauth.com/api/mobile"}
This shows us the first vulnerability in this kind of design. The password used to decrypt the QR code is far too short and simple to be robust against a brute-force attack. To search the entire keyspace using only CPUs can be done with a few dollars on Amazon AWS (see the README on https://github.com/ss23/entrust-identityguard-tools), and can surely be optimized even further with a GPU implementation. There’s an argument to be made that because the decrypted data only contains information that is present in the previous email, it doesn’t result in less security if it can be decrypted, but the fundamental flaw is that people working with these QR codes assume them to not be bruteforcable. This means people are happy to send the QR codes through email (even Entrust themselves, through their IntelliTrust platform, send these codes via email), or transmit them through other insecure means, with the assumption that they’re protected and don’t present a meaningful security risk alone.
Entrust IdentityGuard Registration
At this stage we don’t yet have the underlying TOTP secret, so we need to understand how the Entrust application uses the information we do have. An easy way to verify what is taking place is by scanning the same QR code (or entering the information decoded from it) twice. If the generated codes are the same on both devices, we know the information within the QR code is all that is used to generate the TOTP token. If it’s different, there must be more taking place.
The Entrust application generates unique tokens every time we scan the same QR code, which indicates there must be some kind of other process going on that results in the underlying secret being generated and communicated back to the server. This makes sense, as part of the enrollment process involves submitting a “Registration Code” (not to be confused with an Activation Code) back to the enrollment server. This must mean that whatever the secret is, the server can determine it based on the Registration Code. Luckily, we can once again look at the applications code, and with some reverse engineering, determine what is going on.
Using the information in the QR code, the application generates a “secret” of 2 bytes on the device. This is then combined with the other information and merged into the Registration Code. When the server receives the Registration Code, it can link it back to a specific enrollment, and determine the underlying OTP secret.
To verify this, we can use an example we’ve previously added to the device. If we can generate the same tokens as the application does, we’ll know we’ve obtained the true OTP secret:
ss23@crisp $ ./generate-otp.py 18924-27533 0186-3302-4398-6152 24211-55785
35695cd4c2c90fe30c5cf04f1ccd48ea
To generate a code immediately, run:
oathtool -v --totp=sha256 --digits=6 35695cd4c2c90fe30c5cf04f1ccd48ea
ss23@crisp $ oathtool -v --totp=sha256 --digits=8 35695cd4c2c90fe30c5cf04f1ccd48ea
Hex secret: 35695cd4c2c90fe30c5cf04f1ccd48ea
Base32 secret: GVUVZVGCZEH6GDC46BHRZTKI5I======
Digits: 8
Window size: 0
Step size (seconds): 30
Start time: 1970-01-01 00:00:00 UTC (0)
Current time: 2019-10-24 10:13:12 UTC (1571911992)
Counter: 0x31F840A (52397066)
52112886
This confirms that everything we need to determine the secret is contained within the QR code and Registration Code. Once again, this presents a massive security risk to the solution depending on how it is deployed. There is a natural inclination in a lot of circumstances to simply respond to the person enrolling your token with the Registration Code that was generated. If this is communicated over a persistent channel such as email, an attacker may be able to obtain all the information required to generate a token without anyone knowing. As before, this is not an overt security flaw, but rather a problem with the human parts of the system. If someone is not aware that the QR code and Registration Code contain all that is required to generate new tokens, they’ll not be inclined to protect them. Simply by obfuscating the process of generating these codes, Entrust has substantially decreased how secure their product is in practice.
Entrust IdentityGuard Entropy
Within the previous section, there was another flaw briefly mentioned: only two random bytes are generated on the end-users’ device. As with all the other discussed flaws, this is not an overt security issue, but one of subverting the users’ expectations. After hearing that the Registration Code and QR code contain enough to generate future TOTP outputs, a first reaction is to prevent both of these pieces of information from being found in the same place. In practice, this often means emailing the QR code (as this is an image, and thus hard to communicate through other channels), and sending the Registration Code component through a second channel, such as voice or SMS. This is still a severely flawed practice due to the limited entropy being generated on the end-users’ device.
By observing the QR code, along with a single output of the TOTP token, it is possible to find the correct seed through a brute-force attack. This goes back to the initial problem with TOTP mentioned in the introduction: TOTP is phishable. If an attacker can phish a single output of the token, the attack becomes possible. Something like this becomes even more plausible if you are willing to call an end-user and ask for an “Entrust verification code” or similar without asking for their password. Most users are willing to give out MFA codes over the phone, especially if you emphasize you are not asking for their password.
Putting this into practice with a specific example (with the same values as used previously):
ss23@crisp $ ./crack-otp.py 18924-27533 0186-3302-4398-6152 52112886 1571911992
Possibe valid OTP seed found: 35695cd4c2c90fe30c5cf04f1ccd48ea
To generate a code immediately, run:
oathtool -v --totp=sha256 --digits=6 35695cd4c2c90fe30c5cf04f1ccd48ea
This is the same secret code as we had before, confirming we can now generate new codes the same as the device into the future.
In Summary
Almost every deviation away from a standard TOTP implementation has made the security of the Entrust IdentityGuard solution worse, not through explicit weaknesses, but through the human element — people assuming these changes make the solution more secure than other approaches. Worse still, even Entrust themselves fall victim to these issues with the default configuration of their IntelliTrust trial.
Issues in the design include:
- QR codes are encrypted needlessly, making them seem more secure than they are
- QR code encryption is trivially bruteforcable
- The Registration Code and QR code together contain all that is required to generate new tokens, but this is not obvious to the end-user
- QR codes are emailed out to users, which can be combined with a single TOTP output to determine the underlying seed
To use these tools within your organization, simply head to the GitHub page and check the included README: https://github.com/ss23/entrust-identityguard-tools.