Subject: [OAUTH-WG] State Leakage Attack

From: Daniel Fett <[email-masked]>
Date: Fri, 22 Apr 2016 16:20:41 +0200

Hi all,

During our formal analysis of OAuth we found an attack that allows
CSRF. It is similar to the "code" leak described by Homakov in [1] and
therefore not really surprising. In this attack, the intention for an
attacker is to steal the "state" value instead of the "code" value.

Setting:

In the auth code grant, after authentication to the AS, the user is
redirected to some page on the Client. If this page leaks the
referrer, i.e., there is a link to the attacker's website or some
resource is loaded from the attacker, then the attacker can see not
only code but also state in the Referer header of the request.

The fact that code can leak was described in [1]. Since code is
single-use, it might be already redeemed in most cases when it is sent
to the attacker.

State, however, is not limited to a single use (by 6749 or others) and
therefore can be used by the attacker to mount a CSRF attack and
inject his own code into a (new) auth code grant.

We suggest
a) making state single use, and
b) highlighting to developers the importance of non-leaky redirection
endpoints, and to this end
c) recommending the use of "referrer policies" [2] to mitigate such attacks.

Could somebody confirm whether this attack is new?

Cheers,
Daniel, Guido, and Ralf

[1] http://homakov.blogspot.de/2014/02/how-i-hacked-github-again.html
[2] https://w3c.github.io/webappsec-referrer-policy/
-- 
Informationssicherheit und Kryptografie
Universität Trier - Tel. 0651 201 2847 - H436

---

From: Antonio Sanso <[email-masked]>
Date: Fri, 22 Apr 2016 14:30:17 +0000

hi Daniel

> single-use, it might be already redeemed in most cases when it is sent

probably is not redeemed instead, just because the redirect_uri is not the correct one.
The mitigation that good implemented AS use (also Github) is to follow section 4.1.3 the OAuth core specification [RFC6749], in particular:

"ensure that the "redirect_uri" parameter is present if the "redirect_uri" parameter was included in the initial authorization request as described in Section 4.1.1, and if included ensure that their values are identical."

regards

antonio

> _______________________________________________
> OAuth mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/oauth

---

From: Daniel Fett <[email-masked]>
Date: Fri, 22 Apr 2016 16:35:26 +0200

Hi Antonio,

> "ensure that the "redirect_uri" parameter is present if the "redirect_uri" parameter was included in the initial authorization request as described in Section 4.1.1, and if included ensure that the…

The attack is not based on a manipulation of the redirect_uri. Instead,
a correct redirect_uri is used, but the page loaded from the
redirect_uri contains links or external resources (intentionally or not).

- Daniel

---

From: Antonio Sanso <[email-masked]>
Date: Fri, 22 Apr 2016 14:39:45 +0000

hi Daniel

On Apr 22, 2016, at 4:35 PM, Daniel Fett <[email-masked]<mailto:[email-masked]>> wrote:

Hi Antonio,

Setting:

right. so is not really [1] :) since there there is manipulation using /../../
Now the real question why a legit redirect_uri should contain links to malicious external resources?

regards

antonio

[1] http://homakov.blogspot.ch/2014/02/how-i-hacked-github-again.html

- Daniel

---

From: Daniel Fett <[email-masked]>
Date: Fri, 22 Apr 2016 16:40:06 +0200

> redirect_uri contains links or external resources (intentionally or not).

(This of course describes our attack, not the one by Homakov.)

---

From: Daniel Fett <[email-masked]>
Date: Fri, 22 Apr 2016 16:42:40 +0200

Am 22.04.2016 um 16:39 schrieb Antonio Sanso:
>>> The mitigation that good implemented AS use (also Github) is to
>>> follow section 4.1.3 the OAuth core specification [RFC6749], in
>>> particular:
>>>
>>> "ensure that the "redirect_uri" parameter is present if the
>>> "redirect_uri" parameter was included in the initial authorization
>>> request as described in Section 4.1.1, and if included ensure that
>>> their values are identical."
>>

Of course.

> malicious external resources?

Well, why not? :)

Anyway, developers should be made aware that having external
resources/links on these pages is a bad idea.

- Daniel

---

From: Antonio Sanso <[email-masked]>
Date: Fri, 22 Apr 2016 14:47:07 +0000

On Apr 22, 2016, at 4:42 PM, Daniel Fett <[email-masked]<mailto:[email-masked]>> wrote:

On Apr 22, 2016, at 4:35 PM, Daniel Fett <[email-masked]<mailto:[email-masked]>
<mailto:[email-masked]>> wrote:

Hi Antonio,

Setting:

probably is not redeemed instead, just because the redirect_uri is
not the correct one.
The mitigation that good implemented AS use (also Github) is to
follow section 4.1.3 the OAuth core specification [RFC6749], in
particular:

right. so is not really [1] :) since there there is manipulation using
/../../

Of course.

Now the real question why a legit redirect_uri should contain links to
malicious external resources?

Well, why not? :)

agree about the awareness.
It is more likely that such a page contains resource/links e.g. in the form of <script src=“ to not malicious target. E.g. if the page is using angular than there is <script
src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.js"></script> .
In this case IMHO this is more a privacy issue rather than a real security threat.

regards

antonio

- Daniel

---

From: "[email-masked]" <[email-masked]>
Date: Fri, 22 Apr 2016 19:07:48 +0200

Hi Daniel,

how is the attackers supposed to utilise the leaked state value? I would assume the legit client binds it to a certain user agent, e.g. via the session context, which is not available to the attacker.

best regards,
Torsten.

---

From: "[email-masked]" <[email-masked]>
Date: Fri, 22 Apr 2016 19:07:48 +0200

Hi Daniel,

best regards,
Torsten.

---

From: Guido Schmitz <[email-masked]>
Date: Sat, 23 Apr 2016 12:47:16 +0200

Hi Torsten,

as the state value is supposed to protect the user agent's session
against CSRF attacks, an attacker can use the leaked state value to
perform a CSRF attack against this user agent.

The attacker can, for example, redirect the user agent to the client's
redirection endpoint (again) and by this, overwrite the previously
performed authorization. When the client then contacts some RS (in the
context of the user under attack), it may use an access token linked to
the attacker's account (instead of an access token linked to the user's
account) at the RS. The effects of such an attack are similar to a
session swapping attack. The attacker does not need to access the
session context directly (which may bound to the user agent), as he
instructs the correct user agent to perform these actions.

- Guido

On 22.04.2016 19:07, [email-masked] wrote:
> Hi Daniel,
> 
> how is the attackers supposed to utilise the leaked state value? I would
> assume the legit client binds it to a certain user agent, e.g. via the
> session context, which is not available to the attacker.
> 
> best regards,
> Torsten.
> 
> 
>

---

From: Torsten Lodderstedt <[email-masked]>
Date: Sat, 23 Apr 2016 12:57:14 +0200

Hi Guido,

do I get it right. The attacker is supposed to use the state value in 
order to overwrite the user agent's session state?

best regards,
Torsten.

---

From: Thomas Broyer <[email-masked]>
Date: Sat, 23 Apr 2016 11:17:26 +0000

> instructs the correct user agent to perform these actions.

+1

This is briefly and indirectly touched in
https://tools.ietf.org/html/rfc6819#section-4.4.2.5

      This will ensure that the client is not tricked into completing
      any redirect callback unless it is linked to an authorization
      request initiated by the client.

But this is clearly not explicit (and could very well be just by luck);
note: the key here being "an authorization request initiated by the client".

So, I agree about the validity of the attack and the suggested mitigation
(disclaimer: I'm in no way a security expert, only just a web dev), and I
haven't seen this attack described anywhere.

---

From: André DeMarre <[email-masked]>
Date: Sat, 23 Apr 2016 06:51:20 -0700

A client that implements state values as one-time use would not be affected
by this leakage. The state would be invalidated before it got leaked.

Andre DeMarre

---

From: Thomas Broyer <[email-masked]>
Date: Sat, 23 Apr 2016 13:53:05 +0000

> order to overwrite the user agent's session state?

Most apps only ever remember a single access token, so by re-using the
state the attacker could override the access token by injecting an
authorization code at the redirection_uri, tricking it to accepting the
request by injecting a known (leaked) "state" value.

Flow is:
1. victim app makes a normal OAuth code flow but:
1a. doesn't invalidate the "state" upon return, making it reusable
1b. leaks the "state" to the attacker
It stores the access token into the session.
2. attacker starts a normal OAuth code flow, using the victim app's
redirect_uri, and "intercepts" the "code", which it injects to the victim
app's redirection endpoint, along with the leaked state, through the victim
user's browser. Note that the "code" is bound to the attacker's account.
3. the victim app, validates the "state" and accepts the request, so it
exchanges the code for an access token, and stores it in its session,
replacing the previous one. This means that the victim's session now uses
an access token that's actually bound to the attacker's account.

Easy mitigation is to have one-time state values (i.e. state is somehow
bound to the authorization request, not just the "user session")

Furthermore, IFF the original OAuth code flow was in error (for whichever
reason) and/or was tricked to a bad redirect_uri (like in Homakov's code
leak attack) such that no "code" is redeemed; then the attacker could
possibly use this to link the victim user's account at the victim app to
the attacker's account at the AS (relying on inexistant association of
accounts at the victim app and AS), allowing the attacker to authenticate
to the victim user's account on the victim app using the attacker's
credentials (well-known social login / linked accounts attack).

---

From: André DeMarre <[email-masked]>
Date: Sat, 23 Apr 2016 06:55:42 -0700

I overlooked that one-time use was suggested in the original report; sorry.
I agree with the mitigation, and that client developers should be made
aware.

Andre DeMarre
On Apr 23, 2016 6:51 AM, "André DeMarre" <[email-masked]> wrote:

Andre DeMarre

---

From: Torsten Lodderstedt <[email-masked]>
Date: Sat, 23 Apr 2016 15:56:26 +0200

I don't think this is possible if the client checks whether the state 
actually belongs to its local session before it processes it. Everything 
else seems weird.

Am 23.04.2016 um 15:53 schrieb Thomas Broyer:
>
>
> On Sat, Apr 23, 2016 at 12:57 PM Torsten Lodderstedt 
> <[email-masked] <mailto:[email-masked]>> wrote:
>
>     Hi Guido,
>
> authorization code at the redirection_uri, tricking it to accepting 
> the request by injecting a known (leaked) "state" value.
>
> Flow is:
> redirect_uri, and "intercepts" the "code", which it injects to the 
> victim app's redirection endpoint, along with the leaked state, 
> through the victim user's browser. Note that the "code" is bound to 
> the attacker's account.
> 3. the victim app, validates the "state" and accepts the request, so 
> it exchanges the code for an access token, and stores it in its 
> session, replacing the previous one. This means that the victim's 
> session now uses an access token that's actually bound to the 
> attacker's account.
>
> Easy mitigation is to have one-time state values (i.e. state is 
> somehow bound to the authorization request, not just the "user session")
>
> Furthermore, IFF the original OAuth code flow was in error (for 
> whichever reason) and/or was tricked to a bad redirect_uri (like in 
> Homakov's code leak attack) such that no "code" is redeemed; then the 
> attacker could possibly use this to link the victim user's account at 
> the victim app to the attacker's account at the AS (relying on 
> inexistant association of accounts at the victim app and AS), allowing 
> the attacker to authenticate to the victim user's account on the 
> victim app using the attacker's credentials (well-known social login / 
> linked accounts attack).

---

From: Thomas Broyer <[email-masked]>
Date: Sat, 23 Apr 2016 20:46:29 +0000

On Sat, Apr 23, 2016 at 3:56 PM Torsten Lodderstedt <[email-masked]>
wrote:

> actually belongs to its local session before it processes it.
>

It does so in step 3 below, and it accepts it because: a) the value is the
same, as it leaked and the attacker reinjected the leaked value, and b) the
client didn't invalidate the value after first use in step 1.

---

From: "[email-masked]" <[email-masked]>
Date: Sun, 24 Apr 2016 09:54:15 +0200

Understood. Thanks.

So this is basically a way to circumvent XSRF protection. OWASP has an excellent description of the attack and mitigations https://www.owasp.org/index.php/CSRF_Prevention_Cheat_Sheet - It recommends per-request CSRF tokens for state changes via GET requests. Same conclusion:-)

---

From: John Bradley <[email-masked]>
Date: Sun, 24 Apr 2016 15:31:34 -0500

I described a similar attack at the meeting in Darmstadt.  Using stolen state to inject code from a different session.

We were calling that the cut and paste attack.   The proposed mitigation is ing the draft that Mike and I did.

This was based on the attacker making a new request in a different user agent and using that state.  

In open redirectors draft we do talk about referrer leaking info, and methods to address that.

Checking referrer is a weak protection at best, as that is easily faked in many circumstances.

Are you saying that the proposed mitigation of the AS tying state to code is not sufficient?

John B.

> On Apr 22, 2016, at 9:20 AM, Daniel Fett <[email-masked]> wrote:
> 
> Hi all,
>

---

From: John Bradley <[email-masked]>
Date: Sun, 24 Apr 2016 15:58:34 -0500

I did talk about using “jti" for state replay protection in https://tools.ietf.org/html/draft-bradley-oauth-jwt-encoded-state-05 <https://tools.ietf.org/html/draft-bradley-oauth-jwt-encoded-state-05>

Not that any developer looks at that ID, but I should probably expand the advice for replay protection for state.

We need to remember that a client might have two or more authorization requests in flight at the same time if the user has multiple tabs open.
This is a real issue for clients that developers have shared.  

Supporting that requires more than just keeping a single value that is overwritten.

This sort of attack is why the “code id_token” response type in connect included c_hash and nonce in the Connect id_token.

John B.

> On Apr 24, 2016, at 2:54 AM, [email-masked] wrote:
> 
> Understood. Thanks.
> 
> On Sat, Apr 23, 2016 at 3:56 PM Torsten Lodderstedt <[email-masked] <mailto:[email-masked]>> wrote:
> I don't think this is possible if the client checks whether the state actually belongs to its local session before it processes it.
> 
> It does so in step 3 below, and it accepts it because: a) the value is the same, as it leaked and the attacker reinjected the leaked value, and b) the client didn't invalidate the value after first use in step 1.
>  
>> On Sat, Apr 23, 2016 at 12:57 PM Torsten Lodderstedt <[email-masked] <mailto:[email-masked]>> wrote:
>> Hi Guido,
>> 
>> Most apps only ever remember a single access token, so by re-using the state the attacker could override the access token by injecting an authorization code at the redirection_uri, tricking it to accepting the request by injecting a known (leaked) "state" value.
>> 
>> Flow is:
>> 2. attacker starts a normal OAuth code flow, using the victim app's redirect_uri, and "intercepts" the "code", which it injects to the victim app's redirection endpoint, along with the leaked state, through the victim user's browser. Note that the "code" is bound to the attacker's account.
>> 3. the victim app, validates the "state" and accepts the request, so it exchanges the code for an access token, and stores it in its session, replacing the previous one. This means that the victim's session now uses an access token that's actually bound to the attacker's account.
>> 
>> Easy mitigation is to have one-time state values (i.e. state is somehow bound to the authorization request, not just the "user session")
>> 
>> Furthermore, IFF the original OAuth code flow was in error (for whichever reason) and/or was tricked to a bad redirect_uri (like in Homakov's code leak attack) such that no "code" is redeemed; then the attacker could possibly use this to link the victim user's account at the victim app to the attacker's account at the AS (relying on inexistant association of accounts at the victim app and AS), allowing the attacker to authenticate to the victim user's account on the victim app using the attacker's credentials (well-known social login / linked accounts attack).
>

---

From: Daniel Fett <[email-masked]>
Date: Mon, 25 Apr 2016 15:01:53 +0200

> Checking referrer is a weak protection at best, as that is easily faked in many circumstances.

Note that we do not propose checking the referrer as a mitigation; we
propose using the referrer policy (at the client) to suppress the
referrer (just as in the open redirector draft where it is used at the
AS). So the recommendation here is to use the referrer policy also at
the client.

> Are you saying that the proposed mitigation of the AS tying state to code is not sufficient?

Yes, it is not sufficient as an attacker can request a new code for his
own account at the AS for the same state.

(Note that from draft-bradley-oauth-jwt-encoded-state-05 it does not
become clear how the JTI value comes into play here; you should probably
add some clarification on generating this value and how to check it. An
example would be good.)

-Daniel

---

From: Antonio Sanso <[email-masked]>
Date: Mon, 25 Apr 2016 13:11:53 +0000

hi

> AS). So the recommendation here is to use the referrer policy also at

and just as a corollary Internet Explorer doesn’t seem to support the referrer policy. Maybe Edge…

regards

antonio

---

From: Daniel Fett <[email-masked]>
Date: Mon, 25 Apr 2016 15:15:32 +0200

> and just as a corollary Internet Explorer doesn’t seem to support the referrer policy. Maybe Edge…

Edge does, yes :)

(And this is why having the referrer policy in place is just one part of
our mitigation.)

---

From: John Bradley <[email-masked]>
Date: Mon, 25 Apr 2016 06:30:41 -0700

Inline
> On Apr 25, 2016, at 6:01 AM, Daniel Fett <[email-masked]> wrote:
> 

OK thai is inline with what we recommend in sec 2.3 of https://tools.ietf.org/html/draft-ietf-oauth-closing-redirectors-00

That document is mostly about redirectors on AS.   More needs to go into it on the issue for clients.

> own account at the AS for the same state.
So the attacker gets the leaked state then uses there own browser with the stolen to get a new code in there browser.
Than takes the new code and old state and pastes that into a XSRF attack in the users browser.  
(Sort of the reverse of stealing a leaked code and presenting to the client in the the attackers browser with a new state)

I see how the mitigation of tying state and code together would not work for that.   

However a client using PKCE would not be vulnerable as a side effect of using a different PKCE challenge for each request though a asymmetric PKCE challenge would not have this property.

OK I will grant you that leaking state and using that in a XSRF with a different code to bind and attackers resource to the account is a new twist.

John B.

---

From: John Bradley <[email-masked]>
Date: Mon, 25 Apr 2016 06:36:42 -0700

Yes that policy will be in new browsers but that will not be all browsers for some time (probably not until XP dies)

We are going to have the old browser issue with Token binding as well. 

At some point AS may need to restrict what older browsers can do as they will have different security profiles from current browsers re TLS, token binding, web crypto, web-push, and header policy.

John B.
 
> On Apr 25, 2016, at 6:15 AM, Daniel Fett <[email-masked]> wrote:
>

---

From: Torsten Lodderstedt <[email-masked]>
Date: Mon, 25 Apr 2016 19:29:16 +0200

Hi John,

Am 24.04.2016 um 22:58 schrieb John Bradley:
> I did talk about using “jti" for state replay protection in 
> https://tools.ietf.org/html/draft-bradley-oauth-jwt-encoded-state-05
>
> Not that any developer looks at that ID, but I should probably expand 
> the advice for replay protection for state.

So the JTI makes the state value a per-request anti-XSRF token, right?

>
> We need to remember that a client might have two or more authorization 
> requests in flight at the same time if the user has multiple tabs open.

To prevent mix up (of some kind) :-)

>
> This sort of attack is why the “code id_token” response type in 
> connect included c_hash and nonce in the Connect id_token.

The nonce is the anti XSRF token in this example, right? So it needs to 
be single use as well.

best regards,
Torsten.
>
> John B.
>
>
>> On Apr 24, 2016, at 2:54 AM, [email-masked] 
>> <mailto:[email-masked]> wrote:
>>
>> Understood. Thanks.
>>
>> So this is basically a way to circumvent XSRF protection. OWASP has 
>> an excellent description of the attack and mitigations 
>> https://www.owasp.org/index.php/CSRF_Prevention_Cheat_Sheet - It 
>> recommends per-request CSRF tokens for state changes via GET 
>> requests. Same conclusion:-)
>>
>>
>>
>> Von: Thomas Broyer <[email-masked] <mailto:[email-masked]>>
>> An: Torsten Lodderstedt <[email-masked] 
>> <mailto:[email-masked]>>,Guido Schmitz <[email-masked] 
>> <mailto:[email-masked]>>,[email-masked] <mailto:[email-masked]>
>> On Sat, Apr 23, 2016 at 3:56 PM Torsten Lodderstedt 
>>     I don't think this is possible if the client checks whether the
>>     state actually belongs to its local session before it processes it.
>>
>>
>> It does so in step 3 below, and it accepts it because: a) the value 
>> is the same, as it leaked and the attacker reinjected the leaked 
>> value, and b) the client didn't invalidate the value after first use 
>> in step 1.
>>
>>>     Most apps only ever remember a single access token, so by
>>>     re-using the state the attacker could override the access token
>>>     by injecting an authorization code at the redirection_uri,
>>>     tricking it to accepting the request by injecting a known
>>>     (leaked) "state" value.
>>>
>>>     Flow is:
>>>     2. attacker starts a normal OAuth code flow, using the victim
>>>     app's redirect_uri, and "intercepts" the "code", which it
>>>     injects to the victim app's redirection endpoint, along with the
>>>     leaked state, through the victim user's browser. Note that the
>>>     "code" is bound to the attacker's account.
>>>     3. the victim app, validates the "state" and accepts the
>>>     request, so it exchanges the code for an access token, and
>>>     stores it in its session, replacing the previous one. This means
>>>     that the victim's session now uses an access token that's
>>>     actually bound to the attacker's account.
>>>
>>>     whichever reason) and/or was tricked to a bad redirect_uri (like
>>>     in Homakov's code leak attack) such that no "code" is redeemed;
>>>     then the attacker could possibly use this to link the victim
>>>     user's account at the victim app to the attacker's account at
>>>     the AS (relying on inexistant association of accounts at the
>>>     victim app and AS), allowing the attacker to authenticate to the
>>>     victim user's account on the victim app using the attacker's
>> [email-masked] <mailto:[email-masked]>