PortSwigger's "Stored XSS into anchor href attribute with double quotes HTML-encoded" Walkthrough

This is the second of the two Apprentice level Stored XSS Labs from Portswigger. Before we get started, you’ll need a Portswigger Academy account. This level is completed without Burp Suite, but here’s a blog post to help you set it up for future levels.

After logging in, head over to the lab, located at https://portswigger.net/web-security/cross-site-scripting/contexts/lab-href-attribute-double-quotes-html-encoded. You can find this through the Academy learning path list, or linked within the Stored XSS blog post.

Challenge Information

Click the “Access the Lab” button and you will be taken to a temporary website that is created for your account. This will be in format https://<random string here>.web-security-academy.net/.

This is a stored XSS attack. This means that our malicious input (in the form of some script that executes) will be stored or persist in the webserver somehow (database, etc.) and will be shown to us and likely other users, too.

Here’s the website for the lab:

As before, if we visit an individual blog post (such as https://<random-string>.web-security-academy.net/post?postId=10), there’s a comment section:

Creating our Stored XSS Payload

Our goal is to create a stored XSS attack that calls alert when the commenter name is clicked.

If we make a fake comment with the following attributes:

We see that the username creates the username field (obvious, I know) and the provided website is inserted into the href field:

From this, it appears that the Website field is where we need to focus our efforts, since the lab description says Stored XSS into anchor href attribute.

Before we try things out, let’s figure out what we need to call in order to generate an event from a click. A quick Google search turns up onclick, an event that is triggered from a click (of course), and is added to an element like:

<elementName onclick=alert(1)/>

Lab Solution

We know from the description that " (double quotes) are URL-encoded. If we add a " onclick=alert(1) at the end of our payload, like this:

Here’s our result:

This appears to have worked, but if we click the link, it only takes us to test.com. This might be because of the extra " at the end of the result. What if we add our own closing tag?

Our payload is now: http://test.com" onclick=alert(1)>

Here’s the resulting HTML, which seems to be correct:

Here’s what the comment is rendered as, with the extra " now shown to the user:

And if we click it, we get an alert and solve the lab!