A reflected XSS must sometimes be adjusted to fit into the place where the attacker can inject their code into the victim page. If, for example, the attacker could inject code into an anchor tag’s href attribute, he would need to escape that before he can execute his code. Let’s go through some of the different scenarios that can occur:
The normal reflected XSS
This is what most people will think about when they hear about XSS, this means that the attacker could inject his code straight into the HTML document.
<a href="/messages">Messages - [Injection point]</a> <script>evilcode();</script> <a href="/messages">Messages - <script>evilcode();</script></a>
Recommendation: Make sure that user input is always encoded with HTML Entities.
The DOM XSS
This is basically what I explained shortly above in the example, when an attacker could inject his code into DOM objects and not straight into the document. This means that even if the website filters angle brackets (needed for breaking out of HTML tags), he could still use the element’s attributes to execute it’s script code, by using the element’s DOM events.
Template
<a href="/profile?previouspage=[Injection point]">Profile</a>
Injection
" onclick="evilcode();" title="
Final output
<a href="/profile?previouspage=" onclick="evilcode();" title="">Profile</a>
ecommendation: Make sure that the attributes are encapsulated using double quotation and encode user input with HTML entities. Don’t try to escape quotes (ie \“), that will not work.
The script injection
This reflected XSS attack is based on that the attacker must inject straight into a javascript on the webpage, and this can get very tricky at times since the slightest mistake will give a syntax error making the code unexecutable. A common error that creates these vulnerabilities is using singlequotes together with a HTML entity encoding that doesn’t encode singlequotes. The function htmlentities() in PHP does not encode singlequotes by default.
Template
<script> var pagetitle = 'Welcome [Injection point]!'; document.title = pagetitle; </script>
Injection
';
evilcode(); //
Final output
<script> var pagetitle = 'Welcome '; evilcode(); //!'; document.title = pagetitle; </script>
Recommendation: Make sure the user input is within quotes and escaped properly. If the input is to be used in the HTML document, encode with HTML entities.
Multi-vector XSSes
This attack is based on multiple injections making one vulnerability. If for example the attacker could inject the first part of his payload in one variable and the second in another, bypassing normal XSS filter techniques. This could also happen when the same injection will be printed into the HTML more than once, which in turn can make script injection XSS’es even more complicated. A normal way to solve these problems is to make use of multi-line comments to prevent syntax errors. Sometimes it might even be preferable to have the payload injected more than once, and the attacker could use HTTP parameter pollution to get the desired output.
Template
<script> var pagetitle = 'Welcome to my site!'; if(document.getElementById('[Injection point]') !== null){ document.getElementById('[Injection point]').innerHTML = pagetitle; } document.title = pagetitle; </script>
Injection
*/if(1==1){//'));evilcode(1); /*
Final output
<script> var pagetitle = 'Welcome to my site!'; if(document.getElementById('*/ if(1==1){ //'));evilcode(); /*') !== null){ document.getElementById('*/if(1==1){//'));evilcode(); /*').innerHTML = pagetitle; } document.title = pagetitle; </script>
Recommendation: Make sure you have properly escaped user input and if the input is used in the HTML document, encode it with HTML entities.
Typo squatting (TXSS)
If all else fails, an attacker could look for typo squatting XSS vulnerabilities, which is based on typographic errors from the developers of the victims site. If the developers have spelt the domain name incorrectly when linking to an external script, the attacker could then buy that domain and upload his malicious script, getting an instant persistent XSS on the server.
<!-- Current domain: mysite.com --> <script src="http://mmysite.com/includes/js/stuff.js"></script> <!-- Attacker buys the domain mmysite.com and uploads an infected script to /includes/js/stuff.js -->
Recommendation: Make sure you have proper testing before updating your code in production. Use static values for subdomains and relative paths for the current domain to avoid typographic errors.
Header Injection
If an attacker finds a HRS (Header Response Splitting), he could serve a specially crafted HTTP response to make his code run. For example, if the user is running Internet Explorer, the attacker could inject the header “X-XSS-Protection: 0”, shutting off Internet Explorer’s reflected XSS protection. He could also inject the header “Access-Control-Allow-Origin: [attackers domain]” (http://www.w3.org/TR/cors/), which means that the attacker can send requests with javascript from any domain, stealing sensitive data such as cookies without an actual XSS vulnerability on the victim website!
Template
Content-Type: text/html; charset=UTF-8 Content-Length: 1234 Set-Cookie: username=[Injection point] Connection: close
Injection
nothing\r\nAccess-Control-Allow-Origin: http://evildomain.com\r\nNothing:
Final output
Content-Type: text/html; charset=UTF-8 Content-Length: 1234 Set-Cookie: username=nothing Access-Control-Allow-Origin: http://evildomain.com Nothing: Connection: close
These are some of the most common XSS vulnerabilities found “in the wild” (Okay, HRS is pretty uncommon nowadays, but except for that), but there are some that leverage extensions or plugins such as flash XSS vulnerabilities but I will cover those in another post.
Author: Mathias Karlsson