return of the xss jedi
TRANSCRIPT
RETURN OF XSS JEDI
BY ABE KANG
A Review and XSS and Introduction to DOM based XSS
5 XSS CONTEXTS (HTML PARSER)
HTML
URL
CSS
HTML Attribute
JavaScript (Event Handler Attributes and in
between <script> tags)
DOM BASED XSS (JAVASCRIPT PARSER)
JavaScript can access/modify any of the HTML
elements and attributes of elements displayed
on the page in all of the contexts described on
the previous slide.
DOM based XSS also includes other JS
functions which execute arbitrary code which
can be problematic.
HTML CONTEXT
A HTML context is output which is usually rendered in between HTML markup tags (<TD> tags in this example). Another way of understanding the HTML context is the displayed text (content) in the page.
<TABLE>
<TR><TD>Name:</TD><TD>${actionForm.name}</TD></TR>
<TR><TD>Adress:</TD><TD><%=dbVariable.address%></TD></TR>
<TR><TD>City:</TD><TD><bean:write name=”actionForm” value=”city”/></TD></TR>
<TR><TD>State:</TD><TD><c:out value=”${param.state}</TD></TR>
<TABLE>
HTML Encode to Mitigate
URL CONTEXT
The URL Context consists of user output placed in “src”, “href”,
“background”, and other URL based attributes. Most URL
context exploits are related to passing
“javascript:malicious_code()”, “vbscript:malicious_code()” and
“data:text/html;charset=utf-8;base64,PHNjcmlwdD…” in URL
based attributes.
Notes to keep in mind
The colon needs to be URL encoded or all of the above attacks work
The following will still execute:
<a href=“<%=AllCharsHTMLEncodedVar%>”>Test</a>
<a href=“javascript:<%=AllCharsURLEncoded%>”>Test</a>
<a href=“<%=AllCharHTMLEncoded%>:<%=AllCharsURLEncoded%>”>Test</a>
URL Encode to Mitigate
CASCADING STYLE SHEET (CSS) CONTEXT
The URL Context consists of user output placed in CSS attributes. Most CSS
XSS exploits are related to the “style” attribute.
//the user can select the color
<div style="background-color:<%=request.getParameter(“color”)%>;">
<div style="background-color: green; background-image: url (javascript:bad_code());">
Use a level of indirection to mitigate.
HTML ATTRIBUTE CONTEXT
The HTML tag attribute context consists of user data output in any HTML tag attributes. However there is some discerning that needs to take place here because HTML tag attributes can be in different contexts. For example the “STYLE” attribute of an HTML tag defining a CSS context, URL based attributes (“src”, “background”, and “href”) defining URL based contexts, JavaScript event handlers attributes of HTML tags (“onLoad”,”onClick”, “on*”) defining JavaScript contexts, and the remaining attributes which do not fall in this category (“name”, “value”, “type”, etc.) constituting general HTML attributes.
The following are considered HTML contexts: <input type=“<%=var%>” name=“<%=var2%>” value=“<%=var3%>”/>
If the tags do not use quotes to delimit attributes then space and
other non-alphanumeric characters can be used to delimit attributes
in the tag.
<input type=text name=name value=<%=var3%>/>
The attacker can pass in “Input onclick=attackCode()” to produce:
<input type=text name=name value=Input onclick=attackCode() />
Use HTML Attribute Encoding to mitigate
JAVASCRIPT CONTEXT (EVENT HANDLER)
The JavaScript (JS) context occurs where text is parsed by the JavaScript parser and
executed. The JS context occurs in JS event handler attributes and in between
<script> tags.
JavaScript event handler attributes are HTML tag attributes which handle certain
user events including clicks, mouse movement, focus, blur, etc. The attributes are
easily identified because they start with “on…”.
Remember that text within JS event handlers is raw JS code.
The main problem with JavaScript event handler attributes is they are HTML-
unescaped (at execution time) before they are passed to the JS interpreter. So if you
use HTML output entity encoding to mitigate input data you will be disappointed
because malicious_code() will still execute.
<div onClick=”someJSFunction(\“<%=ESAPI.encodeForHTMLAttribute(
request.getParameter(“input1”))\”%>”> Some Text </div>
JS CONTEXT (EVENT HANDLER MITIGATION)
These steps are for older browsers: 1. If the string literal will eventually end up in HTML you will need to
HTML encode the string. 2. Ensure that the string literal or the string from step 1 above is
JavaScript-escaped using a function which properly escapes dangerous JavaScript characters (example: when escaping a double quote the output value should be \x22 instead of \”. The HTML parser will run before the JavaScript parser allowing the \” to close out the attribute and add other attributes with malicious code inside them.)
3. Make certain that the string literal is enclosed in single quotes 4. Make sure that the surrounding attribute value is enclosed in double
quotes Mitigated example (assuming user input will end up in an HTML
component): <div onClick=”someFunction(„<%=ESAPI.encodeForJavaScript( ESAPI.encodeForHTML(request.getParameter(“input1”)))‟%>)”>
JS CONTEXT (IN BETWEEN <SCRIPT> TAGS)
AKA DOM BASED XSS
Because JavaScript can access/modify any of
the previous contexts that we discussed, the 5
contexts will exist as sub-contexts within the
JavaScript context.
However there are also methods/functions
which are inherently dangerous because they
will execute any string passed to it as code.
HTML 5 has introduced additional points of
interest
DOM XSS IN HTML SUB-CONTEXT
This context in JavaScript code highlights functions which output text to the browser as HTML. element.innerHTML = “<HTML> Tags and markup”;
element.outerHTML = “<HTML> Tags and markup”;
document.write(“<HTML> Tags and markup”);
document.writeln(“<HTML> Tags and markup”);
element.innerHTML = “<%=Encoder.encodeForJS(Encoder.encodeForHTML(untrustedData))%>”;
element.outerHTML = “<%=Encoder.encodeForJS(Encoder.encodeForHTML(untrustedData))%>”;
document.write(“<%=Encoder.encodeForJS(Encoder.encodeForHTML(untrustedData))%>”);
document.writeln(“<%=Encoder.encodeForJS(Encoder.encodeForHTML(untrustedData))%>”);
Since the output is going to HTML you need to HTML encode. Because you are in a JS execution context you need to JS encode to avoid escaping out of the JS quotes.
DOM XSS IN URL SUB-CONTEXT
Remember that any attribute which takes a url falls into this category (background-image, src, location, etc.).
var x = document.createElement(“a”); x.setAttribute(“href”, „<%=Encoder.encodeForJS(Encoder.encodeForURL(userRelativePath))%>‟); var y = document.createTextElement(“Click Me To Test”); x.appendChild(y); document.body.appendChild(x);
var x = document.createElement(“a”); x.href = „<%=Encoder.encodeForJS(Encoder.encodeForURL(userRelativePath))%>‟; var y = document.createTextElement(“Click Me To Test”); x.appendChild(y); document.body.appendChild(x);
Because the parser which is parsing the code is the JS parser (vs the HTML parser), the reverse encoding rules are different. The colon rule (url encoding the colon)still holds true however, HTML encoding does not get reverse encoded. In addition, JS encoding does not stop a javascript: based attack. JS encoding only is used to prevent the attacker from injecting up (escaping out of the quotes).
DOM XSS IN URL SUB-CONTEXT (TESTS) //HTML encoding everything including ": does not work“ This would have worked in an HTML rendering context
var s = "javascript:alert(123)"
//URL encoding everything does not work (colon rule)
var s = "%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%31%32%33%29";
//This works where "javascript:" is not encoded.
var s = "javascript:%61%6C%65%72%74%28%31%32%33%29%0A";
//This does not work but would have worked in an HTML rendering context
var s = "javascript:alert(123)
"
//This works
var s = "javascript:\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0032\u0033\u0029";
//JavaScript encoding everything works as well
var s = "\u006a\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074\u003a\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0032\u0033\u0029"
var link = document.createElement("a");
//link.setAttribute("href", s);
link.href = s;
var text = document.createTextNode("Click Me")
link.appendChild(text);
document.body.appendChild(link);
DOM XSS IN CSS SUB-CONTEXT
Remember that any attribute which sets a CSS attribute will fall into this category.
Most of the expression functionality has been deactivated after IE6. document.body.runtimeStyle.cssText = '1:expression(alert(123))„
Most exploits are related to setting URL attributes on style objects //DNW document.body.style.backgroundImage = "javascript:alert(999)";
//WORKED IE6 document.body.style.backgroundImage = "url(javascript:alert(999))";
//WORKED IE6 document.body.style.backgroundImage = "url(vbscript:Alert(99))";
//WORKED IE6 document.body.background = "javascript:alert(999)"
//WORKED IE6 document.body.background = "vbscript:Alert(99)";
//WORKED IE6 var e = document.createElement("table");
//WORKED IE6 e.setAttribute("background", "javascript:alert('Background')");
//WORKED IE6 var e = document.createElement("table");
//WORKED IE6 e.setAttribute("background", "vbscript:Alert(3333)");
//var e = document.createElement("div");
//The below 4 do not work in IE6
//e.setAttribute("style", "backgroundImage:url(javascript:alert('dynamic DIV'))");
//e.setAttribute("style", "background-image:url(javascript:alert('dynamic DIV'))");
//e.setAttribute("style", "background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029");
//document.body.style = "backgroundImage: url(javascript:alert('999'))";
//Both of the below do NOT work
//e.style.width = "expression(alert(1111))";
//e.setAttribute("style", "width:expression(alert(89898))");
//var e = document.createElement("xss");
//DNW e.setAttribute("style", "xss:expression(alert('XSS'))");
//DNW document.body.style.xss = "expression(alert('XSS'))";
//DNW document.body.style.width = "expression(alert(1111))";
DOM XSS IN HTML ATTTRIBUTE SUB-CONTEXT
Because the HTML attribute contexts inherently includes attributes which are not defined in URL, CSS, and event handler contexts their exploitability is limited.
The one major exception is when setting the text node or attribute of a inherently dangerous tag (<script>, <object>, etc.).
/*Works in FF3.6 but not in IE8 */
var s = document.createElement("script");
var t = document.createTextNode("alert('textNode')");
s.appendChild(t);
document.body.appendChild(s);
document.scripts[1].text = "alert('scripts[1]')";
DOM XSS IN HTML ATTRIBUTE SUB-CONTEXT
(TESTS) //HTML Attribute Context
//Input is "javascript:alert(123)"
//HTML encoding everything including ": does not work"
//var s =
"javascript:alert(&#x
31;23)"
//URL encoding everything does not work
//var s = "%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%31%32%33%29";
//This does not work where "javascript:" is not encoded.
//var s = "javascript:%61%6C%65%72%74%28%31%32%33%29%0A";
//This does not work
//var s = "javascript:alert(123)
"
//This does not work
//var s = "javascript:\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0032\u0033\u0029";
//JavaScript encoding everything does not work as well
//Does not work
//var s =
"\u006a\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074\u003a\u0061\u006c\u0065\u0072\u0074\u0
028\u0031\u0032\u0033\u0029"
//Injecting <script> does not work
//var s = "<\/script><script>alert(123)<\/script>//";
/*
var inp = document.createElement("input");
inp.setAttribute("value", s);
var form1 = document.forms[0];
form1.appendChild(inp);
DOM XSS IN EVENT HANDLER SUB-CONTEXT
Remember that any attribute which is an event handler method
falls into this category (onload, onclick, etc.). You will typically
see it in one or more of the following ways. // “alert(123)” is JavaScript encoded in red below
var s = "\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0032\u0033\u0029”
var inp = document.createElement("input");
inp.setAttribute("onclick", s); // element.setAttribute() will coerce strings to their native types
//or
inp.onclick = new Function ("alert(111)"); // Event handlers are functions not strings
var form1 = document.forms[0];
form1.appendChild(inp);
A key thing to note is that event handlers are function types as
opposed to strings coerced into functions. The setAttribute(“x”, “y”) will
coerce strings to their native attribute types. HTML, and URL encoding
will break the app but keep XSS from executing.
Contrary to the general rule, JavaScript encoding will not stop attacks
here.
DOM XSS IN EVENT HANDLER SUB-CONTEXT
TESTS //JavaScript Event handler Context
//Input is "javascript:alert(123)“ HTML encoding everything including ": does not work"
var s =
"javascript:alert(&#x
31;23)"
//URL encoding everything does not work
var s = "%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%31%32%33%29";
//This does not work where "javascript:" is not encoded.
var s = "javascript:%61%6C%65%72%74%28%31%32%33%29%0A";
//This does not work
var s = "javascript:alert(123)
"
//This does not work because this is not a URL context and javascript:
var s = "javascript:\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0032\u0033\u0029";
//JavaScript encoding everything does work in a JavaScript event handler when using the "javascript:" protocol
//Does work
var s =
"\u006a\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074\u003a\u0061\u006c\u0065\u0072\u0074\u0
028\u0031\u0032\u0033\u0029"
//The following below works in Mozilla
var s = "\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0032\u0033\u0029";
var inp = document.createElement("input");
inp.setAttribute("onclick", s);
var form1 = document.forms[0];
form1.appendChild(inp);
DOM BASED XSS CODE EXECUTION METHODS
There are methods within JavaScript which execute code from a JS string or raw text. eval(…),
setInterval(…),
setTimeout, executeScript(…),
new Function(…),
scriptElement.text = …,
defineSetter(„x‟, eval); x=attackCode;
window[x](y) or top[x](y); //Where x=eval and y=attackCode
window[x] = y; or top[x] = y; // You tell me
str.replace(/.+/, function($1) {//code which operates on $1})
The key thing to remember is that JavaScript encoding is just an equivalent format for representing unicode characters. If you JavaScript encode characters and pass them to the methods above they will still execute.
Remember that /string/.source and String.fromCharCode(12,23....) can be used to create strings.
MISCELLANEOUS JavaScript statements can be terminated by semicolon or new line.
var a =1
var b =2;
You can declare multiple variables on the same line even if they are of different types
var a = 1, b = window.opener, c=“myString”;
You can assign system functions and objects to variables
var o = eval;
o(“alert(213)”);
If you use a Encoding library which JS encodes “ (double quote) to \”. Then you will be able to escape out of a JS event handler.
<input type=“text” onclick=“<%=JSEncodedVar%>” />
The attacker can pass in null” onmouseover=attackCode() x=“
<input type=“text” onclick=“null\” onmouseover=attackCode() x=\“” />
The above attack works because the HTML parser runs before the JavaScript parser.
HTML 5 XSS NOTIFICATIONAPI PHISHING
Shows a Outlook Email Notification in bottom right corner of screen. Only works in
Chrome
function RequestPermission (callback) {
window.webkitNotifications.requestPermission(callback);
}
function showNotification(){
if (window.webkitNotifications.checkPermission() > 0) {
RequestPermission(showNotification);
}
else {
window.webkitNotifications.createNotification("http://www.wf.com/home.png",
"Title", "Body").show();
}
}
HTML 5 XSS WebStorageAPI Poisoning
An attacker can over write Web Storage
window.sessionStorage.setItem(„myFirstKey', untrustedData);
window.localStorage.setItem(„myFirstKey', untrustedData);
window.sessionStorage[“myFirstKey”] = untrustedData;
window.localStorage.myFirstKey = untrustedData;
sessionStorage.setItem(„myFirstKey', untrustedData);
localStorage.setItem(„myFirstKey', untrustedData);
globalStorage….
HTML 5 XSS ClientSide SQL Injection
Request Parameters going to client side SQL
var db = google.gears.factory.create('beta.database');
db.open('dot_store_http___zscaler_paymo_biz_client_2_0_client_html');
var data;
var rs = db.execute('SELECT * FROM __DOJO_STORAGE' + reqParam);
var db = openDatabase('mydb', '1.0', 'my first database', 2 * 1024 * 1024);
db.transaction(function (tx) {
// here be the transaction
// do SQL magic here using the tx object
tx.executeSql('SELECT * FROM __DOJO_STORAGE' + reqParam);
HTML 5 XSS CLIENT-SIDE STORED XSS
Data from localstorage or client DB is sent to vulnerable
methods that we have been discussing
Q&A
?