The lab
Here is how PortSwigger describes it
This lab contains a reflected cross-site scripting vulnerability in the search query tracking functionality where angle brackets and double are HTML encoded and single quotes are escaped.
To solve this lab, perform a cross-site scripting attack that breaks out of the JavaScript string and calls the alert function.
The last lab put us in this exact JavaScript string spot and we escaped by closing the whole script tag, but here the angle brackets are encoded so that door is bricked up, and the way out this time is a gap in how the site escapes our quote.
The idea#
We are back inside a JavaScript string, something like var searchTerms = 'OURINPUT', and the lab has tried to seal every obvious exit. Angle brackets are HTML encoded, so < and > come back as harmless text and the trick from the last lab, breaking out with </script>, is dead on arrival. Double quotes are encoded too, so those are gone. Single quotes are escaped, so a raw ' we send is turned into \' and just sits inside the string. On paper there is no way out.
But there is one character the site never mentions, the backslash. And that omission is the entire exploit, because the site defends our quote by putting a backslash in front of it, and a backslash is only an escape character if the backslash itself is real. If the site does not also escape the backslashes we send, then we can feed in a backslash of our own to cancel out the one the site adds, and suddenly our quote is free again. The whole lab comes down to proving that backslashes are not filtered and then using one against the site.
Step 1 - find the reflection in the Javascript string#
I searched for logicbreaker and looked for it in the page source.

Our input is planted inside a JavaScript string in a script block, the same shape as the previous lab, where the value is later stuffed into a tracking image with document.write. The injection point that matters is that var searchTerms = '...' string.
Step 2 - the quote is escaped and the old trick is gone#
Following the previous lab, the first probe is a single quote, so I searched for test'logicbreaker.

Our ' comes back as \', escaped, so it will not close the string. And unlike last time we cannot fall back on breaking the script element either, because the angle brackets are HTML encoded here, so </script> would just come back as text. Both of the routes we already know are shut, which means we need to look harder at what the site is not touching.
Step 3 - probe the backslash and spot the gap#
The site is clearly willing to add backslashes to defend itself, so the obvious question is what it does with a backslash we send. I searched for test\logicbreaker and read the reflection.
var searchTerms = 'test\logicbreaker'
Our backslash came straight back as a single backslash, untouched. That is the tell. In the previous lab a backslash we sent got doubled into two, which is what kept us out, but here the site leaves it exactly as we typed it. So the site escapes our quotes but forgets to escape our backslashes, and that mismatch is the crack we drive a wedge into.
Step 4 - turn the escaping against itself and solve#
Here is the payload.
\'-alert(1)//
Watch what the site does with it. Our leading \ passes through untouched, and our ' gets escaped to \', so the value that lands in the page is our backslash followed by the site's escaped quote, which reads as this.
var searchTerms = '\\'-alert(1)//'
Now read it the way JavaScript does. The \\ is an escaped backslash, so it collapses to one real backslash character sitting inside the string, and that uses up the backslash the site added for its own escaping. With the site's backslash spent, our ' is left standing on its own and it closes the string for good. From there -alert(1) follows a now finished string, so JavaScript has to evaluate '...' - alert(1) as an expression, and working that out means calling alert(1). The // on the end comments out the original closing quote that the template left behind, so nothing throws a syntax error.
In short, we handed the site a backslash to swallow its own backslash, freed our quote, and the moment the string closed our code ran.

With this, the lab is solved!
