PortSwigger's "Reflected XSS into a JavaScript string with angle brackets HTML encoded" Walkthrough

This is the third writeup of the Reflected XSS Labs from Portswigger. Before we get started, you’ll need a Portswigger Academy account. This level is completed without Burp Suite, but we have 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-javascript-string-angle-brackets-html-encoded. You can find this through the Academy learning path list, or linked within the Reflected 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 reflected XSS attack. This means that our malicious input (in the form of some script that executes) will be reflected onto the page, rather than stored in a database or somewhere else more permanent.

We know from the description that our input will be put into Javascript somehow. Let’s check out the website and figure out how our input is handled.

Here’s the website:

If we put in a search query, it’s shown on the page:

Here’s what it looks like in the HTML (using Dev Tools):

We see that there’s a <script> section that takes our input, assigns it to a searchTerms variable, then does a document.write with the URL encoded (using encodeURIComponent) value.

Our input is injected into a few places: the searchTerms variable, and the document.write() output, which is the <img> tag at the bottom of the screenshot.

What Doesn’t Work

If we use a payload of hi", the resulting HTML and <script> output is as shown:

Our " is URL encoded (via the encodeURIComponent() call), such that we can’t break out of the <img src=""> closing quote and add our own attributes to the img.

Using Hack Trick’s XSS post as a reference, the “Inside Javascript code” section has these options for XSS within Javascript:

If we try the first option, with a payload of hi';</script>, the resulting Javascript looks like this:

Our input is being converted from < and > to &lt; and &gt;.

Let’s try another option on the list. If we use hi'; as our payload, we see this:

The apostrophe is handled as we’d like it to be, where we have closed the var searchTerms single quotes and now have the start of a new Javascript command.

Lab Solution

Now we can add our alert in, using payload hi'; alert(1)

This doesn’t pop an alert, however.

Remember earlier that the Hack Tricks page said that if there is an error in the Javascript code, it will not be executed.

The first line of Javascript code we have created is not valid, since it has the extra '; in it.

var searchTerms = 'hi';alert(1)';
document.write('<img src="/resources/images/tracker.gif?searchTerms='+encodeURIComponent(searchTerms)+'">');

Similar to SQLi labs, we can use a comment to tell the computer to ignore the rest of the command that we’re unable to change. In Javascript, comments look like //.

If we add that to our payload: hi'; alert(1)// for an overall URL of https://<random-string>.web-security-academy.net/?search=hi%27;alert(1)//.

We get an alert!

Here’s the resulting Javascript:

var searchTerms = 'hi';alert(1)//';
document.write('<img src="/resources/images/tracker.gif?searchTerms='+encodeURIComponent(searchTerms)+'">');

This is technically using command injection to do reflected XSS.