This lab uses the HTMLJanitor library, which is vulnerable to . 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.
After accessing the lab, I enabled the FoxyProxy extension to proxy all the web requests through BurpSuite. After navigating a bit through the website, I checked BurpSuite's HTTP history.
I noticed that there are two JavaScript files at the backend: htmlJanitor.js
and loadCommentsWithHtmlJanitor.js
. htmlJanitor.js
is the library itself that contains the sanitization functions, and loadCommentsWithHtmlJanitor.js
is the JavaScript that loads the comments. During the process of loading the comments, it calls sanitization functions on the comment to make sure there is no disallowed HTML.
If I look at this instruction from loadCommentsWithHtmlJanitor.js
:
I can see that I'm allowed to write an input
tag with name, type, and value attributes, and a form
tag with an id.
In the htmlJanitor.js
file, I see heavy use of the attributes
property:
It uses the attributes property to extract and remove the HTML attributes. So the idea is, if I can clobber this property, I can then allow some malicious attributes.
Taking note that I can only use two tags, which are form
and input
, I will use the input
tag to clobber the attributes property by setting an id equal to attributes in the input tag:
To make things clearer, here is an example. Imagine this form with a normal input:
If I open the developer tools in the browser and try to get the form attributes in the console:
But if I change the input to clobber the attributes property:
Then if I try to reaccess the attributes property, I can see that it got modified:
What happens is that the list of attributes gets replaced with the actual input element. So in the lab, when the htmlJanitor
tries to access the attributes on the form, it's just being given the input HTML element, so it won't be able to effectively remove the attributes from the form itself. Now I can build my XSS payload, but I will use the form tag because there is still a filter on the tags. My full payload will be:
When this form has focus, it will trigger the onfocus
event handler and execute the print()
function.
If I fill the comment form of postId=1, for example, and click "Post Comment," I can see a new input field appears. Now, by setting the focus on that input form by specifying its id value with a # preceding it, like the following:
I can see that the print function gets executed. Now the goal is to make this exploit work on the victim's machine. I will use the exploit server to host a malicious page that has an iframe containing the comment form page of a product with an id equal to 1, where I placed the clobbering payload, setting the focus on the custom form to trigger the print function.
My malicious page will have this code:
The setTimeout()
function will execute the code this.src=this.src+'#x'
after 500 milliseconds. The reason I didn't just add that manually when loading the iframe is because of a potential delay problem; it may call for the form but not find it because the DOM didn't fully load yet.
By copying and pasting that payload into the body part of the exploit page in the exploit server and clicking "Store" and "Deliver exploit to victim," I can see that the lab is solved.