Clobbering DOM attributes to bypass HTML filters

3 min read Easy PortSwigger
DOM-based-vulnerabilities
Contents

On this page

The lab

here is how portswigger describes it

This lab uses the HTMLJanitor library, which is vulnerable to DOM clobbering. To solve this lab, construct a vector that bypasses the filter and uses DOM clobbering to inject a vector that calls the print() function. You may need to use the exploit server in order to make your vector auto-execute in the victim's browser.

the last lab used dom clobbering to overwrite a variable the page trusted and this one aims the same technique at something bigger, the sanitizer that is supposed to be keeping us out. we clobber a property the filter itself depends on and the filter stops filtering.

what htmljanitor is ?#

HTMLJanitor is a javascript library that cleans up untrusted html. you hand it some markup and it walks through it and strips out any tags and attributes that are not on its allowlist, so that a comment or a post cannot smuggle in dangerous things like event handlers. it is the doorman that is meant to throw out anything unsafe before the html reaches the page. the trouble is in how this version does the walking, to go through an element's attributes it reads the element's attributes property and loops over it, and attributes is exactly the kind of dom property that clobbering can overwrite.

The idea#

when a form contains a child element that has id=attributes, the browser makes form.attributes point at that child instead of at the real list of the form's attributes. so if the sanitizer reads form.attributes.length to drive its loop, it now gets the input's length, which is undefined, the loop never runs, and none of the form's own attributes are ever checked or removed. that means we can hang a dangerous attribute on the form and the janitor will leave it completely alone. so the plan is one comment that both carries a malicious attribute and clobbers attributes so the filter cannot see it, and then a way to set that attribute off.

Step 1 - Post the clobbering comment#

we go to a blog post and leave this comment which the filter allows through because as far as it can tell, there is nothing to strip.

HTML
<form id=x tabindex=0 onfocus=print()><input id=attributes>
a

here is what each part is doing. the <input id=attributes> inside the form is the clobber, it makes form.attributes resolve to this input, so when the janitor reads form.attributes.length it is undefined and the attribute stripping loop is skipped, leaving the form's own attributes intact. those attributes are the payload, onfocus=print() is the code we want to run, and tabindex=0 makes the form focusable so that it can receive a focus event at all. and id=x gives the form a name we can point at to focus it. so after the filter has run, the form is still sitting on the page with a live onfocus handler on it.

Step 2 - Auto focus the form to fire it#

onfocus only runs when the element gets focus, so we need to focus our form on its own. the url fragment does that, navigating to #x tells the browser to jump to and focus the element with id=x, and since we made it focusable with tabindex, focusing it fires onfocus and calls print. we drive that from an iframe on the exploit server.

HTML
<iframe src="https://your-lab-id.web-security-academy.net/post?postId=3" onload="setTimeout(()=>this.src=this.src+'#x',500)"></iframe>

the iframe loads the blog post, and on load it waits half a second and then appends #x to its own url. the delay matters, the comments are loaded and sanitized by javascript after the page arrives, so we wait so that our form is actually on the page before we try to focus it. once the #x is added, the browser focuses our form, onfocus runs, and print is called. store this on the exploit server and deliver it.

aa

with this, the lab is solved!