DOM XSS in jQuery selector sink using a hashchange event
The following is my documentation on Portswigger’s Academy labs.
Goal: Deliver an exploit that calls print() in the user’s browser.
We are going to commit “blogger sin” and show you the solution first and work our way backward. That’s because I want to be helpful in my learning journey, but also because as someone who cooked professionally, running into recipe blogs that start with a 5k word story about the blogger’s childhood before I can get to the recipe has frustrated me to no end. There will be no hypocrites here.
So let’s break it before we break it down.
Below is a quick look at the site we will be trying to exploit:
To start we’ll deliver the following payload to the site’s URL:
After sending this payload the page reloads with the print prompt ready, however, we have not passed the lab. This is not a failure as at least we have demonstrated that we can use JAVA to manipulate the site.
So, what next? Well, the lab has constructed an exploit server for us to use. We need this because the last payload was really just self-cross scripting, so it will only affect our own browser and not another user. We can use the exploit server to automate the payload and execute the JAVA so that it actually changes the value of the hash (more about that later).
To achieve our goals we’ll be placing our payload into <iframe> the “body” section of the exploit server. Our payload should look something like this:
All we need to do is hit the “Deliver exploit to victim” button and…
The lab is now solved! And there you have it, a recipe before the background. You can now leave if you must, no hard feelings, but if you want to know why this works, stick around and I’ll tell you.
Hopefully, you noticed the “#” at the beginning of our first payload. Well, when we look at the source of the page we find a jQuery event:
What this script is basically doing is looking for a <h2> tag with a # and a string, and then scrolls to that element on the page. This is useful for things like anchor links.
Our possible exploit comes into play by taking advantage of the part of the script looking for said #. We can see this in action by looking for an <h2> in the blog post, and appending that onto our URL like this: url-here.net/#Interviews
The page will automatically scroll to that heading on the page (note: this is case-sensitive). If we change the # we also change the argument passed to the jQuerey contains method. Remember the #<img src= portion of our original payload? Well, we are pointing the page’s script to a hash that we control, and we are using an image tag because images call URLs into play. This will point the script to then lookup a URL, the fun part is that we set that to zero: #<img src=0 This will produce an error, and we take advantage of that with the last part of the payload: onerror=’print()’> See what we did there? We created an error, and, in doing so, had the script print. So why attach this payload to an <iframe>? Because an <iframe> will embed other documents (or in this case, code) into other documents which makes our exploit complete.
Potential Impact of an XSS attack like this
Our current payload (and lab goal) applied print() to the exploit. Though seemingly harmless, there is no reason why we cannot call the alert() function, and from there we can do all kinds of sketchy things— like point the user to another site of our own malicious design. Scammers can use this to lie to a user that there is something wrong with their computer and that it can only be fixed by paying them.
Possible prevention methods
UPDATE! This vulnerability has been patched, so update, update, update!
Notes
I used the following resources in this exercise:
Share this:
Filed under: Cybersecurity,Pentesting,PortSwigger Academy,XSS attack - @ December 17, 2023 9:14 pm
2 thoughts on “DOM XSS in jQuery selector sink using a hashchange event”