A Topic Presents Itself
As I sat down this morning thinking about an appropriate topic for this week's blog post, I quickly found my subject - XSS flaws. The Twitter-verse exploded this morning with an outbreak of an XSS worm that is using the onmouseover event to propagate itself (technically I believe that this is a CSRF attack as it is forcing the user to send a Twitter update that they didn't intend to send... but I digress.). I quickly added this incident into the WASC Web Hacking Incident Database.
How Prevalent is XSS?
Just how big of a problem is XSS? Most web application security statistics projects have it listed right at the top -
OWASP Top 10 Web Application Security Risks for 2010
WASC Web Application Security Statistics
WASC Web Hacking Incident Database
How Can You Protect Yourself?
First of all, make sure that all of your developers read, then reread, and then really sit down and take notes and seriously get a game plan together to address the issues raised in the OWASP XSS Prevention Cheatsheet document. Make sure you understand this section on untrusted data:
Untrusted data is most often data that comes from the HTTP request, in the form of URL parameters, form fields, headers, or cookies. But data that comes from databases, web services, and other sources is frequently untrusted from a security perspective. That is, it might not have been perfectly validated. The OWASP Code Review Guide has a decent list of methods that return untrusted data in various languages, but you should be careful about your own methods as well.
Untrusted data should always be treated as though it contains an attack. That means you should not send it anywhere without taking steps to make sure that any attacks are detected and neutralized. As applications get more and more interconnected, the likelihood of a buried attack being decoded or executed by a downstream interpreter increases rapidly.
Traditionally, input validation has been the preferred approach for handling untrusted data. However, input validation is not a great solution for injection attacks. First, input validation is typically done when the data is received, before the destination is known. That means that we don't know which characters might be significant in the target interpreter. Second, and possibly even more importantly, applications must allow potentially harmful characters in. For example, should poor Mr. O'Malley be prevented from registering in the database simply because SQL considers ' a special character?
The OWASP ModSecurity Core Rule Set (CRS) contains many rules to try and identify malicious XSS payloads for example in the modsecurity_crs_41_xss_attacks.conf file. The XSS payload used in the Twitter attacks today have been posted to PasteBin and if you send it to the CRS Demo you will see that it is detected by many different detection methods.
While input validation and looking for generic attack payloads is useful for identifying attack attempts, it is not the same as identifying the actual underlying application weakness that is exploited by XSS attacks and that is Improper Output Handling. Essentially, what you need is Dynamic Taint Propagation detection where you can track where unstrusted user data is insecurely used within your application. For XSS you need to identify where user supplied data is echoed back to clients in an unescaped form.
Dynamic Taint Propagation with ModSecurity
In CRS v2.0.7, we added an optional ruleset called modsecurity_crs_55_application_defects.conf which, among other things, implements an experimental dynamic taint propagation ruleset to identity if/when/where an application does not properly output encode/escape user supplied data.
# # XSS Detection - Missing Output Encoding # SecAction "phase:1,nolog,pass,initcol:global=xss_list" # # Identifies Reflected XSS # If malicious input (with Meta-Characters) is echoed back in the reply non-encoded. # SecRule &ARGS "@gt 0" "chain,phase:4,t:none,log,auditlog,deny,status:403,id:'1',msg:'Potentially Malicious Meta-Characters in User Data Not Properly Output Encoded.',logdata:'%{tx.inbound_meta-characters}'" SecRule ARGS "([\'\"\(\)\;<>#])" "chain,t:none" SecRule MATCHED_VAR "^.{15,}$" "chain,t:none,setvar:tx.inbound_meta-characters=%{matched_var}" SecRule RESPONSE_BODY "@contains %{tx.inbound_meta-characters}" "ctl:auditLogParts=+E" # # Check to see if TX XSS Data is already in the GLOBAL list. If it is - expire it. SecRule GLOBAL:'/XSS_LIST_.*/' "@streq %{tx.inbound_meta-characters}" "phase:4,t:none,nolog,pass,skip:1" SecRule TX:INBOUND_META-CHARACTERS ".*" "phase:4,t:none,nolog,pass,setvar:global.xss_list_%{time_epoch}=%{matched_var}" # # Identifies Stored XSS # If malicious input (with Meta-Characters) is echoed back on any page non-encoded. SecRule GLOBAL:'/XSS_LIST_.*/' "@within %{response_body}" "phase:4,t:none,log,auditlog,pass,msg:'Potentially Malicious Meta-Characters in User Data Not Properly Output Encoded',tag:'WEB_ATTACK/XSS'"
Keep in mind - this ruleset's goal is not to try and identify malicious payloads but rather to indirectly identify possible stored/reflected XSS attack surface points by flagging when an application resources does not properly output escape user supplied data. An advantage to this approach is that we don't have to be as concerned with evasion issues as they rules are not looking for malicious payloads. Instead, they will monitor as normal users interact with the application and will alert if the application does not correctly handle the data.
Using this type of application weakness detection, it is possible to identify the underlying issues in the application and get a plan together to address them rather than perpetually playing "Whack-a-Mole" with inbound attacks.