Cross-Site Scripting (XSS)

Photo by Joan Gamell on Unsplash

Cross-Site Scripting (XSS)

·

5 min read

Cross-Site Scripting (XSS) is a common and vulnerable attack that every advanced tester is aware of. It is regarded as one of the most dangerous attacks on web applications, with potentially disastrous consequences.

Example

<HTML>
 <HEAD>
 <TITLE>BABY XSS</TITLE>
 </HEAD>
 <BODY ONLOAD="CONVERT()" ONHASHCHANGE="CONVERT()">
 <H1>BABY XSS</H1>
 <TEXTAREA ID="INPUT" ONCHANGE="WINDOW[LOCATION][HASH]=WINDOW[ENCODEURI](INPUT[VALUE])" STYLE="WIDTH:400;HEIGHT:300"></TEXTAREA>
 <IFRAME ID="OUTPUT" STYLE="WIDTH:400;HEIGHT:300"></IFRAME>
 <SCRIPT>
    TOUPPERCASE = "\164\157\125\160\160\145\162\103\141\163\145";
SUBSTR = "\163\165\142\163\164\162";

    ENCODEURI = "\145\156\143\157\144\145\125\122\111";
    DECODEURI = "\144\145\143\157\144\145\125\122\111";
    VALUE = "\166\141\154\165\145";
    SRCDOC = "\163\162\143\144\157\143";
    CONTENTWINDOW = "\143\157\156\164\145\156\164\127\151\156\144\157\167";
    PARENT = "\160\141\162\145\156\164";
    LOCATION = "\154\157\143\141\164\151\157\156";
    HASH = "\150\141\163\150";
    WINDOW = OUTPUT[CONTENTWINDOW][PARENT];

    CONVERT = () => {
        INPUT[VALUE] = WINDOW[DECODEURI](WINDOW[LOCATION][HASH][SUBSTR](1));
        OUTPUT[SRCDOC] = INPUT[VALUE][TOUPPERCASE]();
    }
</SCRIPT>
</BODY>
</HTML>

We can see that this whole piece of code is uppercased. Also, the strings in the code inside the script tag are not readable and obfuscated.

So we input this whole piece of JavaScript code into javascript deobfuscator. This is what we get.

TOUPPERCASE = "toUpperCase";
SUBSTR = "substr";
ENCODEURI = "encodeURI";
DECODEURI = "decodeURI";
VALUE = "value";
SRCDOC = "srcdoc";
CONTENTWINDOW = "contentWindow";
PARENT = "parent";
LOCATION = "location";
HASH = "hash";
WINDOW = OUTPUT[CONTENTWINDOW][PARENT];
CONVERT = () => {
  INPUT[VALUE] = WINDOW[DECODEURI](WINDOW[LOCATION][HASH][SUBSTR](1));
  OUTPUT[SRCDOC] = INPUT[VALUE][TOUPPERCASE]();
};

Analyzing

Now that the code has been made readable, we can clean it up and figure out how this page works.

Line 7 shows that whenever the content in the text area changes, a URL-encoded version of the content is appended to the current URL after a # (the hash part of the URL).

<TEXTAREA ID="INPUT" ONCHANGE="window.location.hash=window.encodeURI(INPUT.value)" STYLE="WIDTH:400;HEIGHT:300"></TEXTAREA>
<!-- the cleaned code above is equivalent to the original -->
In Line 5, we can see that whenever the page is loaded or the hash part in the current URL is changed, the CONVERT function is called.
<BODY ONLOAD="CONVERT()" ONHASHCHANGE="CONVERT()">
The CONVERT function is essentially replacing the content in the text area with the URL-decoded form of the hash part of the current URL and also setting the srcdoc attribute of the output iframe to the uppercased form of the content in the text area.
CONVERT = () => {
  document.getElementById("INPUT").value = window.decodeURI(window.location.hash.substr(1)); // substr(1) removes the '#' prefix
  document.getElementById("OUTPUT").srcdoc = INPUT.value.toUpperCase();
}; // the above code is cleaned and is equivalent to the original

XSS Attack Procedure

Because the hash portion of the current URL updates in response to the content in the input text area, it functions as a "state-saving-and-restoring" function. This means that when we type something in the text area, the hash part of the current URL is updated as the input is saved. When we send the URL to the victim, the content in the input text area is restored from the hash portion of the URL once the page loads.

To perform XSS, we must find a way to execute JavaScript in the victim's browser so that we can gain access to sensitive information (e.g., cookies) stored in his browser. To accomplish this, we can use the iframe srcdoc mechanism, which allows us to inject source documents, including JavaScript code, into the iframe document. If we use JavaScript code as the input when the victim loads the page given a URL, the input content is restored and the JavaScript code is executed in the victim's browser.re being inserted into the output iframe's srcdoc attribute.

It's worth noting that HTML tags are case-insensitive, whereas JavaScript variables are. This is significant in this challenge because, despite the lack of escaping or encoding, the input content is uppercased (in Line 9) before being inserted into the output iframe's srcdoc attribute.

This means that if we directly inject something like script>alert(1)/script> into the output iframe as the code will become ```