Format Injection Vulnerability in Duo Security Web SDK
Format Injection is not a new bug, but it was never described as a subclass of A1 Injection. You probably already hate me for giving it a name (at least I didn’t create a logo!) but calling it an “injection” is too general.
The idea is very similar to SQL injections but instead of breaking quotes '
with user input and changing the query, we are breaking custom delimiters /:|,;&
and changing the signed data.
This is how Duo Security’s Web integration works:
-
The user logs in the client app with valid username/password and receives TX token requesting 2nd factor authentication and APP token proving that the user actually passed first authentication step.
-
Now the user exchanges TX token for AUTH token with Duo API (using Duo Push, SMS or a phone call). AUTH token proves the user successfully passed second authentication step.
-
With previously obtained APP token and AUTH token the user is sent to /final_login endpoint which makes sure both tokens are valid and belong to the same username. The
verify_response
method returnsusername
and you now can log the visitor in the account with returnedusername
.
The system is built in a way that even if SKEY is leaked the attackers won’t be able to log in arbitrary accounts because they don’t have your secret AKEY and they can’t forge valid APP tokens. We found a neat format injection in a way Duo signs the APP token. Advisory ID: DUO-PSA-2015-001
Duo Security has identified an issue in certain versions of the Duo Web SDK that could allow attackers to bypass primary and secondary authentication if they have separately gained access to the Duo integration’s secret key, and can create valid usernames containing pipe characters (
|
).
Note: This issue does not affect any Duo-authored integrations; it only affects custom integrations developed using affected versions of the Web SDK.
The severity is low because to sign into arbitrary account you still need a valid AUTH token which means you need to compromise the SKEY. However if your app is affected don’t hesitate to rotate your AKEY.
Conditions: the victim uses Ruby, PHP, Perl, Java or ColdFusion SDKs. Also pipe symbol is allowed in usernames and username field is used as Duo ID (it can be user id or email, where pipe symbol is impossible).
See this piece of code from their Ruby library:
If we manage to create a user with username=victim||9999999999
the APP token we get for it will be parsed the same way as token for the user with username=victim.
If it’s still not clear look at the concatenated strings:
The app signs victim|IKEY|12345678
for the victim user. user, ikey, exp = string.split('|')
returns user=victim
and exp=12345678
The app signs victim||9999999999|IKEY|12345678
for the attacker. user, ikey, exp = string.split('|')
returns user=victim
and exp=9999999999
(the token is valid forever).
More examples
-
Anything like
val+DELIMITER+user_input+DELIMITER+...
or[user_input,val2,val3].join(':')
is very likely to be vulnerable to format injection. -
openURL('https://oauth/?client_id=1&client_secret=2&code='+params[:unescaped_code])
in hand-made API and OAuth implementations. Injecting code=&client_id=new_client_id&client_secret=new_client_secret
leads to replacing client credentials with new values and authentication bypass. -
'{"val":"'+user_input+'"}'
or'<xml>'+user_input+'</xml>'
, because XSS is a format injection too. -
See our Puzzle #1
-
Many payment gateways with custom data formats. This is how Liqpay and WalletOne signs orders (no delimiters, just sorted alphabetically and concatenated. I am not even going to comment that)