Exploiting XSS to bypass CSRF defenses

3 min read Easy PortSwigger
XSS
Contents

On this page

The lab

here is how portswigger describes it

This lab contains a stored XSS vulnerability in the blog comments function. To solve the lab, exploit the vulnerability to steal a CSRF token, which you can then use to change the email address of someone who views the blog post comments.

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

Quick word on CSRF#

before the lab it helps to know what we are up against. a csrf attack, short for cross site request forgery, is when a malicious page gets a logged in victim's browser to fire off a request to a site they are signed into, quietly performing an action on their behalf, like changing their email, because the browser tacks on their session cookies automatically. it is a whole topic on its own and we will be covering the dedicated csrf labs soon.

csrf token is the usual defence against that. it is a random, unpredictable string the server generates, ties to your session, and tucks into the form as a hidden field. when the form is submitted the server checks the token matches the one it issued, and since an attacker forging request from some other site has no way to guess it

and here is the twist that makes the whole thing work. a csrf token assumes the attacker cannot see it, but xss breaks that assumption because our code runs inside the victim's own browser on the very same site. we are not forging blindly from the outside, we are standing on the inside, so we can just read the token off the victim's page and hand it right back.

step 1 - Log in and inspect the change email request#

first i logged in with the provided credentials, wiener:peter.

1111

there is a change email feature on the account page, so to see how it is guarded i intercepted the request and looked at what it sends.

2222

the post body carries two parameters, the new email and a csrf token. so a blind forged request would fail, because it would not carry a valid token. that tells us the plan, we need to load the account page pull the current csrf token out of it and only then send the change email request with that token attached

step 2 - Write the xss that steals the token and changes the email#

since the xss is in the comments, we can make the victim's browser do all of that for us. here is the payload

javascript
<script>
var req = new XMLHttpRequest()
req.onload = handleResponse
req.open('get','/my-account',true)
req.send()
function handleResponse() {
    var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1]
    var changeReq = new XMLHttpRequest()
    changeReq.open('post', '/my-account/change-email', true)
    changeReq.send('csrf='+token+'&[email protected]')
}
</script>

in plain terms it runs in two moves. the first request does a get of /my-account, the victim's own account page, which is where the csrf token sits in a hidden field. when that page comes back, handleResponse runs and the regex name="csrf" value="(\w+)" plucks the token value straight out of the html. armed with a real token, the second request then does a post to /my-account/change-email with a body of csrf= the stolen token email=administrator@test. test, which is a valid change email request as far as the server is concerned

step 3 - Drop it in a comment and solve#

now we just deliver it. open any post and submit that script as a comment.

3333

from here anyone who views the comment, including the simulated victim, has their browser silently read its own csrf token and use it to change their email to ours, and the lab solves itself the moment that happens.

with this, the lab is solved!