Drupal Core Color XSS Vulnerabilities

25 August 2011
Recently the Drupal team released a security upgrade to the Drupal core to versions 6.21, 6.22, 7.1 and 7.2. These updates fixed several security flaws, the most commonly exploitable of which is a flaw in the core color module that allowed an attacker who could gain access to the color picker widget (for instance through the theme administration) to perform cross site scripting (XSS) attacks. This flaw resulted in a persistent XSS vulnerability in the Drupal core.

Recently the Drupal team released a security upgrade to the Drupal core to versions 6.21, 6.22, 7.1 and 7.2. These updates fixed several security flaws, the most commonly exploitable of which is a flaw in the core color module that allowed an attacker who could gain access to the color picker widget (for instance through the theme administration) to perform cross site scripting (XSS) attacks. This flaw resulted in a persistent XSS vulnerability in the Drupal core. The other two vulnerabilities addressed, a reflected XSS and a file permissions bypass can be mitigated by limiting error output and occurs only when using a specific module (node access), respectively.

Exploiting the Color Vuln

Exploiting the color XSS flaw is a little tricky, since it involves writing unfiltered data to the style sheet. Cascading style sheets can be used to execute arbitrary JavaScript with assistance from specially crafted files. In this example we'll use a script.xml file that for the sake of simplicity, lives in the sites/default/files directory (this is the default location for uploaded files so it's feasible for an attacker to upload an XML file to this location through several methods). This file contains the following content, cribbed directly from a StackOverflow post (http://stackoverflow.com/questions/476276/using-javascript-in-css):

<?xml version="1.0"?>
<bindings xmlns="http://www.mozilla.org/xbl" xmlns:html="http://www.w3.org/1999/xhtml">

<binding id="mycode">
  <implementation>
    <constructor>
      alert("XBL script executed.");
    </constructor>
  </implementation>
</binding>

</bindings>

Now, if an attacker can inject the text "-moz-binding: url(/sites/default/files/script.xml#mycode);" into the style sheet they can cause a JavaScript alert box to show in Firefox browsers. To do this an attacker simply has to log in to the Drupal target site, and navigate to the color picker of the Garland theme at ?q=admin/build/themes/settings/garland. Next they can update the "Text color" selection so that it reads "#333; -moz-binding: url('/sites/default/files/script.xml#mycode')" and click the "Save configuration" button. The resulting screen should show the alert box. Care should be taken, however, because munging up this input can result in a white screen of death, and no clear way to reset the data.

Source of the Issue

The essential root of the flaw is the fact that the color module doesn't actually filter input to disallow semi-colons, which are used to delimit style attributes in CSS. This allows an attacker to escape out of the color definition and add their own attributes to style elements.

Wider Implications

Unfortunately this attacks works just as well on Drupal 5 as it does on Drupal 6, but there is no official patch to mitigate the vulnerability in Drupal 5. Looking at a diff of the modules/color/color.module between Drupal 6.19 and Drupal 6.22 it is easy to see the changes that were made. The following line was added to the function color_form_alter:

 $form['#validate'][] = 'color_scheme_form_validate';

And this in turn calls the following new function that will sanitize user input:

/**
 * Validation handler for color change form.
 */
function color_scheme_form_validate($form, &$form_state) {
  // Only accept hexadecimal CSS color strings to avoid XSS upon use.
  foreach ($form_state['values']['palette'] as $key => $color) {
    if (!preg_match('/^#([a-f0-9]{3}){1,2}$/iD', $color)) {
      form_set_error('palette][' . $key, t('%name must be a valid hexadecimal CSS color value.', array('%name' => $form['color']['palette'][$key]['#title'])));
    }
  }
}

Although there is no official update to the Drupal 5 core, applying the following patch will mitigate this issue in Drupal 5:

--- color.module	2011-06-01 12:51:41.184645306 -0400
+++ color.module	2011-06-01 13:23:14.699205275 -0400
@@ -33,6 +33,7 @@ function color_form_alter($form_id, &$fo
         '#theme' => 'color_scheme_form',
       );
       $form['color'] += color_scheme_form(arg(4));
+      $form['#validate']['color_scheme_form_validate'] = array();
       $form['#submit']['color_scheme_form_submit'] = array();
     }
   }
@@ -51,6 +52,18 @@ function color_form_alter($form_id, &$fo
 }
 
 /**
+ * Validation handler for color change form.
+ */
+function color_scheme_form_validate($form, &$form_state) {
+  // Only accept hexadecimal CSS color strings to avoid XSS upon use.
+  foreach ($form_state['palette'] as $key => $color) {
+    if (!preg_match('/^#([a-f0-9]{3}){1,2}$/iD', $color)) {
+      form_set_error('palette][' . $key, t('%name must be a valid hexadecimal CSS color value.', array('%name' => $key)));
+    }
+  }
+}
+
+/**
  * Callback for the theme to alter the resources used.
  */
 function _color_page_alter(&$vars) {