XSS (Cross-site Scripting) allows an attacker to execute a dynamic script (Javascript, VbScript) in the context of the application. This allows several different attack opportunities, mostly hijacking the current session of the user or changing the look of the page by changing the HTML on the fly to steal the user's credentials. This happens because the input entered by a user has been interpreted as HTML/Javascript/VbScript by the browser.
XSS targets the users of the application instead of the server. Although this is a limitation, since it allows attackers to hijack other users' session, an attacker might attack an administrator to gain full control over the application.
Impact
There are many different attacks that can be leveraged through the use of XSS, including:
Hi-jacking users' active session
Changing the look of the page within the victims browser.
Mounting a successful phishing attack.
Intercept data and perform man-in-the-middle attacks.
Remedy
The issue occurs because the browser interprets the input as active HTML, Javascript or VbScript. To avoid this, all input and output from the application should be filtered. Output should be filtered according to the output format and location. Typically the output location is HTML. Where the output is HTML ensure that all active content is removed prior to its presentation to the server.
Prior to sanitizing user input, ensure you have a pre-defined list of both expected and acceptable characters with which you populate a white-list. This list needs only be defined once and should be used to sanitize and validate all subsequent input.
There are a number of pre-defined, well structured white-list libraries available for many different environments, good examples of these include, OWASP Reform and Microsoft Anti Cross-site Scripting libraries are good examples.
A Cookie was not marked as secure and transmitted over HTTPS. This means the cookie could potentially be stolen by an attacker who can successfully intercept and decrypt the traffic or following a successful MITM (Man in the middle) attack.
Impact
This cookie will be transmitted over a HTTP connection, therefore if this cookie is important (such as a session cookie) an attacker might intercept it and hijack a victim's session. If the attacker can carry out a MITM attack, he/she can force victim to make a HTTP request to steal the cookie.
Actions to Take
See the remedy for solution.
Mark all cookies used within the application as secure. (If the cookie is not related to authentication or does not carry any personal information you do not have to mark it as secure.))
Remedy
Mark all cookies used within the application as secure.
Required Skills for Successful Exploitation
To exploit this issue, the attacker needs to be able to intercept traffic. This generally requires local access to the web server or victim's network. Attackers need to be understand layer 2, have physical access to systems either as way points for the traffic, or locally (have gained access to) to a system between the victim and the web server.
Netsparker identified a web page that discloses server side source code. An attacker can obtain server side source code of web application, which can contain sensitive data such as database connection strings, usernames and passwords along with the technical and business logic of the application.
Impact
Depending on the nature of the source code disclosed an attacker can mount one or more of the following types of attacks:
Access the database or other data resources. With the privileges of the account obtained attempt to read, update or delete arbitrary data from the database.
Access password protected administrative mechanisms such as "dashboard", "management console" and "admin panel" potentially leading to gull control of the application.
Develop further attacks by investigating the source code for input validation errors and logic vulnerabilities.
Actions to Take
Confirm exactly what aspects of the source code is actually disclosed; due limitations of these types of vulnerability it might not be possible to confirm this in all instances. Confirm this is not intended functionality.
If it is a file required by the application, change its permissions to prevent public users from accessing it. If it is not, then remove it from the web server
Ensure that the server has all the current security patches applied.
Remove all temporary and backup files from the web server.
Required Skills for Successful Exploitation
This is dependent on the information obtained from source code. Uncovering these forms of vulnerabilities does not require high levels of skills. However a highly skilled attacker could leverage this form of vulnerability to obtain account information for databases or administrative panels, ultimately leading to control of the application or even the host the application reside on.
The Server responded with an HTTP status 500. This indicates that there is a server-side error. Reasons may vary. The behavior should be analysed carefully. If Netsparker is able to find a security issue in the same resource it will report this as a separate vulnerability.
Impact
The impact may vary depending on the condition. Generally this indicates poor coding practices, not enough error checking, sanitization and whitelisting. However there might be a bigger issue such as SQL Injection. If that's the case Netsparker will check for other possible issues and report them separately.
Remedy
Analyse this issue and review the application code in order to handle unexpected errors, this should be a generic practice which does not disclose further information upon an error. All errors should be handled server side only.
"Auto Complete" was enabled in one or more of the form fields. These were either "password" fields or important fields such as "Credit Card".
Impact
Data entered in these fields will be cached by the browser. An attacker who can access the victim's browser could steal this information. This is especially important if the application is commonly used in shared computers such as cyber cafes or airport terminals.
Remedy
Add the attribute autocomplete="off" to the form tag or to individual "input" fields.
Actions to Take
See the remedy for the solution.
Find all instances of inputs which store private data and disable autocomplete. Fields which contain data such as "Credit Card" or "CCV" type data should not be cached. You can allow the application to cache usernames and remember passwords, however, in most cases this is not recommended.
Re-scan the application after addressing the identified issues to ensure that all of the fixes have been applied properly.
Required Skills for Successful Exploitation
Dumping all data from a browser can be fairly easy and there exist a number of automated tools to undertake this. Where the attacker cannot dump the data, he/she could still browse the recently visited websites and activate the auto-complete feature to see previously entered values.
Cookie was not marked as HTTPOnly. HTTPOnly cookies can not be read by client-side scripts therefore marking a cookie as HTTPOnly can provide an additional layer of protection against Cross-site Scripting attacks..
Impact
During a Cross-site Scripting attack an attacker might easily access cookies and hijack the victim's session.
Actions to Take
See the remedy for solution
Consider marking all of the cookies used by the application as HTTPOnly (After these changes javascript code will not able to read cookies.
Remedy
Mark the cookie as HTTPOnly. This will be an extra layer of defence against XSS. However this is not a silver bullet and will not protect the system against Cross-site Scripting attacks. An attacker can use a tool such as XSS Tunnel to bypass HTTPOnly protection.
Netsparker identified that the target web server is disclosing Apache Coyote version in the HTTP response. This information can help an attacker to gain a greater understanding of the systems in use and potentially develop further attacks targeted at the specific version of Apache.
Impact
An attacker can look for specific security vulnerabilities for the version identified in the SERVER header. The attacker can also use this information in conjunction with the other vulnerabilities in the application or the web server.
Remedy
Configure your web server to prevent information leakage from the SERVER header of its HTTP response.
Netsparker found e-mail addresses on the web site.
Impact
E-mail addresses discovered within the application can be used by both spam email engines and also brute force tools. Furthermore valid email addresses may lead to social engineering attacks .
Remedy
Use generic email addresses such as contact@ or info@ for general communications, remove user/people specific e-mail addresses from the web site, should this be required use submission forms for this purpose.
/* FILE: /js/utils.js */ var globalAnimationSpeed = 300;function object(o) { function F() {}; F.prototype = o; return new F();}/* Extending Date Object with daysInMonth function. Javascript's Date functions lets you overflow the day parameter by * creating a date in the previous month. We can check how far the result overlaps into the next month and figure out * how many days there are in a month */if (Date.prototype.getDaysInMonth == null) { Date.prototype.getDaysInMonth = function() { return 32 - new Date(this.getFullYear(), this.getMonth(), 32).getDate(); };}Infusion('Server');Infusion.Server.secureServerString = "";Infusion.Server.version = "";Infusion.Server.setSecureServerString = function(str) { Infusion.Server.secureServerString = str;};Infusion.Server.setVersion = function(str) { Infusion.Server.version = str;};Infusion('UserAgent');Infusion.UserAgent.isIE7 = (document.all && !window.opera && window.XMLHttpRequest);Infusion.UserAgent.isFF2 = false;if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)) { Infusion.UserAgent.isFF2 = new Number(RegExp.$1) == 2;}/* orderBy accepts three parameters. The target page, the key to order by, and the direction of sort. */function orderBy(key, target, dir) { window.location = target + "?order=" + key + "&dir=" + dir;}/* from main */function handleResponse(msg) { if (msg != '' && msg != 'null' && msg != null) alert(msg);}function go(cat) { var what = document.getElementById("report" + cat); if (what.options.selectedIndex > 0) { window.location = what.options[what.options.selectedIndex].value; }}function show(cat) { var what = document.getElementById("report" + cat); var diver = document.getElementById("report" + cat + "Desc"); var arry = eval("arry" + cat); if (what.options.selectedIndex == 0) { diver.innerHTML = "Please select a report from the drop down above"; } else { diver.innerHTML = arry[what.options.selectedIndex]; }}/* from main */function ResizeOuter(width, height) { currWidth = document.body.clientWidth; currHeight = document.body.clientHeight; endHeight = height - currHeight; endWidth = width - currWidth; window.resizeBy(endWidth, endHeight);}function resize(width, height) { ResizeInner(width, height);}function resizeHeight(height) { currWidth = document.body.clientWidth; currHeight = document.body.clientHeight; currHeight = document.body.clientHeight; endHeight = height - currHeight; endWidth = 0; window.resizeBy(endWidth, endHeight);}function ResizeInner(width, height) { window.innerWidth = width; window.innerHeight = height;}function ResizeAndGo(width, height, url) { ResizeOuter(width, height); location = url;}/* adds ability to register more than one event to window.onload */var onloaders = new Array();function runOnLoads() { for (i = 0; i < onloaders.length; i++) { try { eval(onloaders[i]); } catch(error) { alert(error.message); } }}function addLoader(obj) { onloaders[onloaders.length] = obj;}function doUnload() { return false;}window.onload = runOnLoads;function closeWindow() { if (window.opener) { if (!window.opener.closed) { if (reloadParent) { window.opener.location.reload(); window.opener.focus(); } } } window.close();}function openEmail() { window.open("/Mail/home.jsp", "mail", "toolbars=no,resizable=yes");}function openMyAccount(url) { if (window.opener != null && window.opener.parent.opener != null) { window.opener.parent.opener.location.href = url; window.opener.parent.opener.focus(); } else if (window.opener != null) { window.opener.location.href = url; window.opener.focus(); } else { window.location.href = url; }}function validEmail(email) { return email.match("^([a-zA-Z0-9_\\.-])+@(([a-zA-Z0-9-])+\\.)+([a-zA-Z0-9])+$");}Infusion('ProductOptionValues');Infusion.ProductOptionValues.moveUp = function (optionIndex, Id) { Infusion.ProductOptionValues.move(true, optionIndex, Id)};Infusion.ProductOptionValues.moveDown = function (optionIndex, Id) { Infusion.ProductOptionValues.move(false, optionIndex, Id);};Infusion.ProductOptionValues.move = function (up, optionIndex, Id) { var i = 0; var found = false; var productOptionTable = document.getElementById("ProductOptionTable"); var rowAdjacent; var rowCurrent; var adjacentOptionIndex; var adjacentId; var limitAdjacent; var limitCurrent; var adjacentRowIdx; var currentRowIdx; var funcStrAdjacent = up ? "Down" : "Up"; // We set the following four values based on the var imgStrAdjacent = funcStrAdjacent.toLowerCase(); // direction we move the current row. If we are var funcStrCurrent = up ? "Up" : "Down"; // moving the current row up, then its image var imgStrCurrent = funcStrCurrent.toLowerCase(); // and function strings are "up", while the var titleStrAdjacent = imgStrAdjacent; // image and function strings for the adjacent var titleStrCurrent = imgStrCurrent; // cell is "down". The opposite applies when for // the case where we move the current cell down. while (!found && i < productOptionTable.rows.length) { found = (productOptionTable.rows[i].id == "ProductOption" + optionIndex + "_" + Id); i++; } i--; adjacentRowIdx = up ? (i - 1) : (i + 1); currentRowIdx = i; rowAdjacent = document.getElementById(productOptionTable.rows[adjacentRowIdx].id); rowCurrent = document.getElementById(productOptionTable.rows[currentRowIdx].id); /* * We define the following limits to handle cases where the cells are either at the top of the row, or the * bottom. We need to appropriately set the controls (up and/or down) based on the location of the rows. * The limits seem "backward", but the reason is that we actually swap the contents of the two rows. So * the content of the "adjacent" row is the original content of the "current" row and vice-versa. This * sounds pretty convoluted (and probably is) so it might be better to think of the "adjacent" row as the * "row we are moving the current row to". Consider the case where we are moving the current cell "up". * In that case, the limit we could encounter is where the index of the adjacent row is 1 (topmost row). * Hence, the "adjacent limit" is 1. Looking at the "current limit", we can see that this is the row to * which we moved the contents of our original "adjacent cell". Since this row is effectively moving * "down", the limit for this row would be the index of the last row in the table. */ limitAdjacent = up ? 1 : (productOptionTable.rows.length - 1); limitCurrent = up ? (productOptionTable.rows.length - 1) : 1; Infusion.ProductOptionValues.swapContent(rowAdjacent.cells[0], rowCurrent.cells[0]); Infusion.ProductOptionValues.swapContent(rowAdjacent.cells[1], rowCurrent.cells[1]); Infusion.ProductOptionValues.swapContent(rowAdjacent.cells[2], rowCurrent.cells[2]); Infusion.ProductOptionValues.swapContent(rowAdjacent.cells[3], rowCurrent.cells[3]); /* * Here, we grab the option index and id of the adjacent row. We then update the id of the row to reflect * the swap that we just performed. */ adjacentOptionIndex = rowAdjacent.id.replace(/ProductOption/, "").replace(/_[0-9]+$/, ""); adjacentId = rowAdjacent.id.replace(/ProductOption[0-9]+_/, ""); rowAdjacent.id = rowAdjacent.id.replace(/_[0-9]+/, "_" + Id); rowCurrent.id = rowCurrent.id.replace(/_[0-9]+/, "_" + adjacentId); /* * We need to check for the case where we have only two rows in the table. This if-statement checks for that * condition so that we can set our control appropriately ("down" for the top row and "up" for the bottom). */ if (productOptionTable.rows.length > 3) { if (adjacentRowIdx == limitAdjacent) { rowAdjacent.cells[3].innerHTML = "<a title = \"Move this row " + titleStrAdjacent + "\" href = \"javascript:Infusion.ProductOptionValues.move" + funcStrAdjacent + "(" + adjacentOptionIndex + ", " + Id + ")\"><img border = 0 src=\"../images/" + imgStrAdjacent + "arrow.png\" alt=\"" + imgStrAdjacent + " arrow\" /></a>"; rowCurrent.cells[3].innerHTML = "<a title = \"Move this row up\" href = \"javascript:Infusion.ProductOptionValues.moveUp(" + optionIndex + ", " + adjacentId + ")\"><img border = 0 src=\"../images/uparrow.png\" alt=\"up arrow\" /></a> <a title = \"Move this row down\" href = \"javascript:Infusion.ProductOptionValues.moveDown(" + optionIndex + ", " + adjacentId + ")\"><img border = 0 src=\"../images/downarrow.png\" alt=\"down arrow\" /></a>"; } else if (currentRowIdx == limitCurrent) { rowAdjacent.cells[3].innerHTML = "<a title = \"Move this row up\" href = \"javascript:Infusion.ProductOptionValues.moveUp(" + adjacentOptionIndex + ", " + Id + ")\"><img border = 0 src=\"../images/uparrow.png\" alt=\"up arrow\" /></a> <a title = \"Move this row down\" href = \"javascript:Infusion.ProductOptionValues.moveDown(" + adjacentOptionIndex + ", " + Id + ")\"><img border = 0 src=\"../images/downarrow.png\" alt=\"down arrow\" /></a>"; rowCurrent.cells[3].innerHTML = "<a title = \"Move this row " + titleStrCurrent + "\" href = \"javascript:Infusion.ProductOptionValues.move" + funcStrCurrent + "(" + optionIndex + ", " + adjacentId + ")\"><img border = 0 src=\"../images/" + imgStrCurrent + "arrow.png\" alt=\"" + imgStrCurrent + " arrow\" /></a>"; } else { rowAdjacent.cells[3].innerHTML = rowAdjacent.cells[3].innerHTML.replace(/\([0-9]+/g, "(" + adjacentOptionIndex); rowCurrent.cells[3].innerHTML = rowCurrent.cells[3].innerHTML.replace(/\([0-9]+/g, "(" + optionIndex); } } else { rowAdjacent.cells[3].innerHTML = "<a href = \"javascript:Infusion.ProductOptionValues.move" + funcStrAdjacent + "(" + adjacentOptionIndex + ", " + Id + ")\"><img border = 0 src=\"../images/" + imgStrAdjacent + "arrow.png\" alt=\"" + imgStrAdjacent + " arrow\" /></a>"; rowCurrent.cells[3].innerHTML = "<a href = \"javascript:Infusion.ProductOptionValues.move" + funcStrCurrent + "(" + optionIndex + ", " + adjacentId + ")\"><img border = 0 src=\"../images/" + imgStrCurrent + "arrow.png\" alt=\"" + imgStrCurrent + " arrow\" /></a>"; } Infusion.ProductOptionValues.updateOptions(optionIndex, adjacentId, adjacentOptionIndex, Id);};Infusion.ProductOptionValues.swapContent = function (obj1, obj2) { var temp; temp = obj1.innerHTML; obj1.innerHTML = obj2.innerHTML; obj2.innerHTML = temp;};Infusion.ProductOptionValues.updateOptions = function (optionIndex1, Id1, optionIndex2, Id2) { var url = "/Product/processProductOptions.jsp"; var post = "type=value&view=edit&prodOptValId1=" + Id1 + "&prodOptValIdx1=" + optionIndex1 + "&prodOptValId2=" + Id2 + "&prodOptValIdx2=" + optionIndex2 + "&prodOptId=" + document.getElementById("ProductOptionDb0Id").value; ajax(url, post, false);};Infusion('Utils');Infusion.Utils.getBase = function() { var base; if (window.parent) { base = window.parent; } else if (window.opener) { base = window.opener; } else { base = window; } return base;};Infusion.Utils.evalScripts = function(scriptString) { var newScript = document.createElement('script'); newScript.type = "text/javascript"; newScript.className = "dynamicScript"; if (YAHOO.util.Event.isIE) { newScript.text = scriptString; } else { var s = document.createTextNode(scriptString); newScript.appendChild(s); } document.getElementsByTagName('body')[0].appendChild(newScript);};Infusion.Utils.getInputFieldByIdOrName = function(idOrName) { return jQuery("input#" + idOrName).get(0) || jQuery("input[name='" + idOrName + "']").get(0);};Infusion.Utils.waitToUpdate = function(value, fieldId, counter, maxRetry) { counter = counter || 1; maxRetry = maxRetry || 25; var field = jQuery('#' + fieldId); if ((field.val() != value) && (counter <= maxRetry)) { field.val(value); setTimeout('Infusion.Utils.waitToUpdate("' + value + '", "' + fieldId + '", ' + (counter++) + ', ' + maxRetry + ')', 500); }};Infusion.Utils.crossDomainAjax = function(url, post, callbackName) { var head = document.getElementsByTagName("head")[0]; var script = document.getElementById("crossDomainAjaxScript"); if (script) { head.removeChild(script); } script = document.createElement("script"); script.id = "crossDomainAjaxScript"; script.type = "text/javascript"; script.src = url + "?" + post + "&callBack=" + callbackName; head.appendChild(script);};// Name: Get CSS Property// Language: JavaScript// Author: Travis Beckham | squidfingers.com// Description: Retrieve a CSS property from inline and external sources// Compatibility: IE4+, NS6+, Safari 1.3+ ( Opera 8+ tested ok so far, comment by windgazer.nl)// --------------------------------------------------// From: http://squidfingers.com/code/snippets/?id=getcsspropInfusion.Utils.getCSSProp = function(element, prop) { if (element.style[prop]) { // inline style property return element.style[prop]; } else if (element.currentStyle) { // external stylesheet for Explorer return element.currentStyle[prop]; } else if (document.defaultView && document.defaultView.getComputedStyle) { // external stylesheet for Mozilla and Safari 1.3+ prop = prop.replace(/([A-Z])/g, "-$1"); prop = prop.toLowerCase(); return document.defaultView.getComputedStyle(element, "").getPropertyValue(prop); } else { // Safari 1.2 return null; }};/* Extremely useful findPosX and findPosY for statically positioned elements from http://blog.firetree.net/2005/07/04/javascript-find-position/ I've renamed them to findTop and findLeft to conform to CSS. I've also added findBottom and findRight. */Infusion.Utils.findLeft = function findLeft(obj) { var curleft = 0; if (obj.offsetParent) while (1) { curleft += obj.offsetLeft; if (!obj.offsetParent) break; obj = obj.offsetParent; } else if (obj.x) curleft += obj.x; return curleft; obj.offset;};Infusion.Utils.findTop = function findTop(obj) { var curtop = 0; if (obj.offsetParent) while (1) { curtop += obj.offsetTop; if (!obj.offsetParent) break; obj = obj.offsetParent; } else if (obj.y) curtop += obj.y; return curtop;};Infusion.Utils.findRight = function findRight(obj) { return document.body.offsetWidth - Infusion.Utils.findLeft(obj) - obj.offsetWidth;};Infusion.Utils.findBottom = function findBottom(obj) { var curbottom = 0; if (obj.offsetParent) while (1) { curbottom += obj.offsetBottom; if (!obj.offsetParent) break; obj = obj.offsetParent; } else if (obj.y) curbottom += obj.y; return curbottom;};/* Removes units from CSS attributes and returns values as float */Infusion.Utils.parseAttribute = function(attr) { attr = (attr == null || undefined) ? "0" : attr; //hack for IE return parseFloat(attr.replace(/em|ex|px|in|cm|mm|pt|pc|%/));};Infusion.Utils.toAMPM = function(hour, minutes) { var time = ""; minutes = (minutes == 0) ? "00" : minutes; if (hour >= 12) { if (hour > 12) { hour -= 12; } time = hour + ":" + minutes + " pm"; } else { if (hour == 0) { hour = 12; } time = hour + ":" + minutes + " am"; } return time;};Infusion.Utils.getTotalWidth = function(obj) { var Utils = Infusion.Utils; return (Utils.parseAttribute(Utils.getCSSProp(obj, "margin-left")) + Utils.parseAttribute(Utils.getCSSProp(obj, "padding-left")) + Utils.parseAttribute(Utils.getCSSProp(obj, "border-left-width")) + Utils.parseAttribute(Utils.getCSSProp(obj, "width")) + Utils.parseAttribute(Utils.getCSSProp(obj, "margin-right")) + Utils.parseAttribute(Utils.getCSSProp(obj, "padding-right")) + Utils.parseAttribute(Utils.getCSSProp(obj, "border-right-width")));};Infusion.Utils.getTotalHeight = function(obj) { var Utils = Infusion.Utils; return (Utils.parseAttribute(Utils.getCSSProp(obj, "margin-top")) + Utils.parseAttribute(Utils.getCSSProp(obj, "padding-top")) + Utils.parseAttribute(Utils.getCSSProp(obj, "border-top-width")) + Utils.parseAttribute(Utils.getCSSProp(obj, "height")) + Utils.parseAttribute(Utils.getCSSProp(obj, "margin-bottom")) + Utils.parseAttribute(Utils.getCSSProp(obj, "padding-bottom")) + Utils.parseAttribute(Utils.getCSSProp(obj, "border-bottom-width")));};Infusion.Utils.fixApostrophes = function(numParams) {..