tl;dr
- Dom clobbering to clobber document.body
- Bypassing Dompurify dom clobbering protection
- Dom clobbering using form tags
š Initial analysis
We are given an application where there’s html injection. Looking at the server.js
file we can see the main functionality which allows HTML injection.
|
|
However there is no easy XSS as the input HTML is sanitized using Dompurify and there is also a CSP.
Looking at the adminbot .
|
|
The admin bot types the flag in the flag field and our HTML , and takes a screenshot of the rendered page and returns it.
But we can’t see the flag as there is a removeFlag.js which removes the flag from the DOM quickly .
|
|
š„· Attack plan
So we have to somehow stop the removeFlag.js from removing the flag from th DOM so that the screenshot will contain the flag.
Since i had HTML injection the first idea that came into my mind was Dom Clobbering. We can clobber document’s properties using the embed, form, iframe, image, img,object
HTML tags using the name attribute.
For eg if I inject <form name="body">
, document.body will return the form
tag instead of the documents body contents.
But however there’s still another problem Dompurify has DOM Clobbering protection. Dompurify will remove the id
and name
attributes from HTML tags if the value of those attributes are existing properties of the document Object.
So we cant give <form name=body>
as Dompurify will remove that attribute .
This is the relevant code that does this in Dompurify.
|
|
Bypassing Dompurify’s protection š
When i looked into how the sanitization is implemented there seems to be changes made to the sanitized HTML by removing the body tags .
|
|
This is a bad practise, to modify or to make changes to the HTML after it has been sanitized by Dompurify.
So now we can give <form name="<body>body">
Dompurify wont remove this as there is not property in the Document object called <body>body
and after it remove’s the body tags it will become <form name="body">
which gets rendered and will clobber the body successfully .
Now we can give a p tag inside the form tag with class attribute flag
which will be returned when let els = document.body.querySelectorAll('.flag')
is called and that p tag will get removed instead of the real flag.
š Final Payloads
|
|
we could have also gotten a 1-click XSS using
|
|