The lab
Here is how PortSwigger describes it
This lab blocks all HTML tags except custom ones.
To solve the lab, perform a cross-site scripting attack that injects a custom tag and automatically alerts document.cookie.
The idea#
There are two ideas doing the work here, and it is worth sitting with both before touching the lab.
The first is custom tags. A browser does not keep a fixed list of tags it will accept. If you write <xss> it will happily create an element for it, even though there is no such thing in HTML. It just treats an unknown tag as a plain inline element and moves on. That matters because a filter that blocks danger by name can only block names it already knows, so <img> and <script> are on its list while <xss> never crossed its mind.
The second idea is the word automatically in the task. A tag on its own does nothing, it needs an event handler to run our code, the same idea from the last lab where an event is just a thing that happens to an element and the handler says run this JavaScript when it does. But we are not allowed to wait for the victim to click anything, the alert has to fire on its own. The event we can force without any help is focus. An element fires onfocus the moment it becomes focused, and a browser will focus an element for us if we point the URL at it. Put a #name on the end of a URL and the browser jumps to the element with that id, and if that element is allowed to hold focus, it gets focused. So the whole plan is a custom tag that we can focus on demand.
Step 1 - confirm the reflection and watch a normal tag die#
The vulnerability is in the search box, so the first move is the ordinary one, drop in a normal payload and see what happens.
<img src=1 onerror=alert(1)>
It does not go through. The response comes back telling us the tag is not allowed, exactly like the WAF lab before this. So real tags by name are a dead end here, and there is no point grinding through a list of them because the lab has already told us they are all blocked.
Step 2 - slip past with a custom tag#
The lab description is basically handing us the way in. All tags are blocked except custom ones, so let us test a tag that does not exist and see if the filter even notices it.
<xss>logicbreaker</xss>
This time there is no complaint. The browser accepts our invented xss element and the filter has nothing to say about it, because it is not a name on any block list. That is the foothold. The catch is that a bare custom tag just sits there on the page doing nothing useful, so the next job is to give it a way to run code and a way to set that code off by itself.
Step 3 - make the custom tag fire code on its own#
We hang an event handler on the tag and then arrange for that event to happen without the victim lifting a finger. Here is the search value we are aiming for.
<xss id=x onfocus=alert(document.cookie) tabindex=1>#x
Read it one attribute at a time.
<xss ...> is our custom tag, the part the filter waves through. id=x gives the element a name so we can point at it from the URL. tabindex=1 is the quiet hero, because normally only things like links and form fields can take focus, and adding a tabindex makes any element focusable, our made up tag included. onfocus=alert(document.cookie) is the payload, it says the moment this element is focused, pop up the cookie. And the #x on the very end is not part of the tag at all, it is the URL fragment, the browser reads it as go find the element with id x. So when the page loads with that fragment, the browser jumps to our xss element, focuses it because we made it focusable, and the focus fires onfocus, which runs alert(document.cookie). Everything sets itself off in a chain, no clicking required.
Step 4 - deliver it so it fires on the victim#
The task wants this to happen automatically and against the victim, not just in our own browser, so we serve it from the exploit server. The reliable way to make the fragment focus trigger is to send the victim's browser on a fresh navigation to our crafted URL, which we do by setting location from a tiny script. Here is what goes on the exploit server.
<script>
location = 'https://YOUR-LAB-ID.web-security-academy.net/?search=%3Cxss+id%3Dx+onfocus%3Dalert%28document.cookie%29%20tabindex=1%3E#x'
</script>
The search value is URL encoded so it survives the trip, and decoded it is exactly the tag we built above, <xss id=x onfocus=alert(document.cookie) tabindex=1> with the #x fragment tacked on the end. When the victim opens our page, the script sends their browser to the lab with our custom tag sitting in the search results and the #x telling the browser which element to focus. The tag renders, the browser focuses it, onfocus runs, and the cookie is alerted in their session.
Swap in your own lab id, deliver it to the victim, and the alert fires on their side.
With this, the lab is solved!
