This lab reflects your input in a JavaScript URL, but all is not as it seems. This initially seems like a trivial challenge; however, the application is blocking some characters in an attempt to prevent XSS attacks.
To solve the lab, perform a attack that calls the alert
function with the string 1337
contained somewhere in the alert
message.
After accessing the lab, I enabled the FoxyProxy extension to proxy all requests through Burp Suite and then started navigating the site. One request caught my attention:
Its response contained an interesting canonical link tag inside a div
responsible for returning to previous pages:
Clicking this link runs the fetch
function with the given arguments, and notably, the postId
parameter is part of the fetch function's configuration object. If I can escape this argument declaration and add my own, I can successfully exploit this XSS vulnerability.
The question is, why am I considering adding multiple arguments to the fetch function, and will that break its functionality? In JavaScript, the number of additional arguments doesn’t matter as long as the required ones are present. For example, here it accepts two arguments:
/analytics
: the URL the fetch function will access.
{method:'post',body:'/post%3fpostId%3d1'}
: the configuration object of the fetch function.
Since these objects are well-declared, adding more arguments is acceptable as long as the syntax is correct.
To build the payload, I need to inject at the body level of the configuration argument. I will start by providing a &
symbol to add a parameter in the query string of the URL, preventing the URL from breaking:
/post?postId=1&
Next, I need to escape the configuration object {method:'post',body:'/post?postId=1'}
by adding a }
to close it properly:
/post?postId=1&'}
At this stage, the payload looks like this in the canonical tag:
{method:'post',body:'/post?postId=1&'}'}
I successfully escaped the object and can now add arguments using the ,
character. For example:
{method:'post',body:'/post?postId=1&'},ARG1,ARG2,ARG3'}
However, the characters }'
at the end will break the payload. I need to include them as part of an argument. Instead of '}'
, I use {x:''}
by adding a ,
to count as an argument, then adding {x:''}
to build the object at that argument:
{method:'post',body:'/post?postId=1&'},ARG1,ARG2,ARG3,{x:''}
Next, I'll build the rest of the payload to trigger the alert function. For the first argument, I will use an arrow function:
This function uses the throw
statement with provided values. The onerror=alert
sets an event handler that triggers an alert on error. The throw
statement outputs an error message, triggering the alert with the message 1337
.
To bypass blocked characters like ()
, ;
, and spaces, I modify the payload:
I removed blocked characters and replaced spaces with comments to spoof the space character.
Next, I call this function in the payload as the next argument. I redefine the toString
function to point to my function and trigger it with a simple instruction. When JavaScript parses it, my instruction will use the predefined toString
function to run my function instead.
Now, when toString
is called, it runs as my function x
. To trigger it:
Since window
is not a string, JavaScript uses the toString
function to convert it, thus running my function x
.
The final payload, incorporating all parts as arguments to the fetch function, looks like this:
When I copy and paste this payload into the URL in the browser, the lab is solved, though the alert popup doesn’t appear immediately because the canonical link tag is a back link. By scrolling down the page and clicking on Back to Blog
, the alert is triggered, and an alert box pops up.