Cross-site request forgery

Cross-site request forgery (CSRF) is a fairly serious attack, usually involving malicious social engineering:

  1. A user logs into an application (e.g. a banking site)

  2. An attacker sends this user an email with a specially crafted URL, a hidden form, or an image with a malicious src

  3. When executed (e.g. the user clicks a link, loads a page or image), the malicious payload makes a request to the application that the user is already logged into, leveraging the active session in the browser for authorization

An example of this exploit in action is a user's email address being changed so that an attacker can use an application's email-based password reset feature to grant themselves access.

CSRF payloads

If the application can be updated using GET requests, the malicious payload could be embedded in an img tag:

<img src="http://[host]/change-password.php?newPassword=hackerpassword">

The above GET request is a little contrived since a lot of application changes (e.g. account updates) happen when a user submits a form with POST data. But CSRF payloads can also be delivered using hidden web forms which automatically submit POST data when a user loads a specially crafted page sent by the attacker:

<html>
  <head>
    <title>Malicious web form</title>
  </head>
  <body onload="document.evil_bank_form.submit()">
    <form action="http://bank.com/transfer" method="POST" name="evil_bank_form" style="display: none;" target="hidden_results">
      <input type="text" name="amount" value="5000" />
      <input type="text" name="to_account" value="12345" />
    </form>
     <iframe name="hidden_results" style="display: none;"></iframe>
  </body>
</html>

In the above example, when a user is tricked into loading this web page, the evil web form performs a bank transfer to the attacker's account, leveraging the user's active browser session with the bank. The form also has a target which displays the results in a hidden iframe so that the user does not notice the malicious request.

For testing purposes, Burp Suite can automatically generate a proof-of-concept CSRF payload, but you have to verify that there isn't a unique token in the test payload (e.g. a form element with a random string). There are a few ways to do this:

  1. Run the payload twice to see if the server rejects it for being a duplicate or expired request

  2. Remove or alter anything that looks like a token from the form elements or GET parameters and see if the payload still works

  3. Replace the token value with a string of the same length and see if the payload still works

  4. Leave the token value blank and see if the payload still works

Generally speaking, if one of the above actions throws an error, the application has some anti-CSRF protections which limit exploitation. Sessions might also be set to expire quickly, making CSRF attacks less viable.

Further reading

Last updated