Drupal 6 Profile (core) Module XSS Vulnerability

30 November -0001

Description of Vulnerability:

Drupal (http://drupal.org) is a robust content management system (CMS) written in PHP and MySQL that provides extensibility through hundreds of third party modules. The profile module is provided as part of the Drupal 6 core modules and contains several arbitrary script injection vulnerabilities that can allow users with the 'administer users' permission to inject arbitrary HTML into category names and explanations. This vulnerability was discovered in Drupal 7 and is public (http://drupal.org/node/611532) thus this report serves only to call out the vulnerability in Drupal 6.

Systems affected:

Drupal 6.15 was tested and shown to be vulnerable

Mitigating factors:

Attacker must have 'administer users' and 'access administration pages" permissions in order to exploit this vulnerability.

Proof of concept:

    Install Drupal 6.15.
  1. Enable the profile module from Administer -> Site building -> Modules
  2. Go to Administer -> User management -> Profiles and click on 'single-line textfield'
  3. Enter "<script>alert('xss1');</script>" for Category
  4. Enter "<script>alert('xss2');</script>" for Explanation
  5. Fill in arbitrary values for other fields and click 'Save field' button
  6. Observe the category XSS on the resulting page
  7. Click Administer -> Users, and select a user and click the 'Edit' link
  8. Click the "<script>alert('xss1');</script>" tab at the top of the form
  9. Observe the second XSS on the resulting page.

Drupal 6 Patch

Applying the following patch mitigates these threats.

--- drupal-6.15/modules/profile/profile.admin.inc	2008-10-16 08:43:08.000000000 -0400
+++ drupal-6.15.patched/modules/profile/profile.admin.inc	2010-03-03 14:33:44.740024567 -0500
@@ -25,7 +25,7 @@ function profile_admin_overview() {
     $form[$field->fid]['name'] = array('#value' => check_plain($field->name));
     $form[$field->fid]['title'] = array('#value' => check_plain($field->title));
     $form[$field->fid]['type'] = array('#value' => $field->type);
-    $form[$field->fid]['category'] = array('#type' => 'select', '#default_value' => $field->category, '#options' => array());
+    $form[$field->fid]['category'] = array('#type' => 'select', '#default_value' => check_plain($field->category), '#options' => array());
     $form[$field->fid]['weight'] = array('#type' => 'weight', '#default_value' => $field->weight);
     $form[$field->fid]['edit'] = array('#value' => l(t('edit'), "admin/user/profile/edit/$field->fid"));
     $form[$field->fid]['delete'] = array('#value' => l(t('delete'), "admin/user/profile/delete/$field->fid"));
diff -up drupal-6.15.new/modules/profile/profile.module drupal-6.15.clean/modules/profile/profile.module
--- drupal-6.15.new/modules/profile/profile.module	2009-01-12 05:09:19.000000000 -0500
+++ drupal-6.15.clean/modules/profile/profile.module	2010-03-03 14:32:54.749038065 -0500
@@ -341,7 +341,7 @@ function _profile_form_explanation($fiel
     $output .= ' '. t('The content of this field is kept private and will not be shown publicly.');
   }
 
-  return $output;
+  return check_plain($output);
 }
 
 function profile_form_profile($edit, $user, $category, $register = FALSE) {