DOM XSS in jQuery selector sink using a hashchange event
Link to lab: https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-jquery-selector-hash-change-event
To solve the lab, deliver an exploit to the victim that calls the print() function in their browser.
To start the lab click the ‘Access the Lab’ button.
When we begin the lab we will be greeted with a blog page featuring a variety of blog posts. Don’t worry if the content differs from the screenshot. PortSwigger Labs can modify the content each time the lab is initiated.
Analyzing the JavaScript in the application we discover the use of the following code.
$(window).on('hashchange', function(){ var post = $('section.blog-list h2:contains(' + decodeURIComponent(window.location.hash.slice(1)) + ')'); if (post) post.get(0).scrollIntoView(); });
What does this code do? The code listens for changes in the URL hash (the part after #) using the hashchange event and automatically scrolls to a blog post title in the <h2> tags that matches the hash value when the event is triggered.
Viewing the HTML we can the <h2> tags and what we can reference.
If we copy an <h2> tag’s text and append it to the URL with a #, pressing Enter will navigate to the matching title, but this will only work once, because the hashchange event won’t fire again unless the hash value actually changes.
We can attempt a basic XSS to prove out a POC with the payload #<img src=x onerror=alert(1)>
. The alert will pop up once, but multiple attempts won’t trigger it again unless the hash value changes, since the hashchange event only fires when the hash actually changes.
Using an iframe tag we can attempt to exploit the payload on a more consistent basis. We can leverage the following snippet. Make sure for your payload that you update the src attribute with your target URL.
<iframe src="https://0a9600dc0460190480cd302c00150061.web-security-academy.net/#" onload="this.src += '<img src=1 onerror=print()>' " hidden="hidden"></frame>
When the iframe loads it modifies it’s own src by appending a new hash with a malicious payload. This changes the URL fragment (the part after #), which triggers the hashchange event inside the iframe.
We can test our payload by clicking the View exploit button to make sure everything is working correctly.
If everything looks good and we will see the print() function fire off. We can now click the Deliver exploit to victim button.
By successfully delivering the JavaScript payload to the victim we’ve effectively solved the lab!
That completes the lab! Well done! If you found this helpful, please send me a tweet and tell me what you thought! Feedback is always appreciated!
Jarrod