Open source software security

Drupal Download Count Module XSS Vulnerability

30 November -0001
Vulnerability Report April 4, 2011 14:30 (GMT - 4:00)

Description of Vulnerability:

Drupal (http://drupal.org) is a robust content management system (CMS) written in PHP and MySQL. The Drupal Download Count module (http://drupal.org/project/download_count) is designed to keep track of file downloads on Drupal sites. This module contains multiple cross site scripting (XSS) vulnerabilities due to the fact that it fails to sanitize user supplied input before display. Download Count was unpublished at version 6.x-1.3 for similar problems (SA-CONTRIB-2010-052 -http://drupal.org/node/803728).

Systems affected:

Drupal 6.19 with Download Count 6.x-1.5 was tested and shown to be vulnerable.

Impact

User could inject arbitrary scripts into pages affecting site users. This could result in administrative account compromise leading to web server process compromise. A more likely scenario would be for an attacker to inject hidden content (such as iframes, applets, or embedded objects) that would attack client browsers in an attempt to compromise site users' machines. This vulnerability could also be used to launch cross site request forgery (XSRF) attacks against the site that could have other unexpected consequences.

Mitigating factors:

In order to exploit this vulnerability the attacker must have credentials to an authorized account that has been assigned the permissions to administer download count. This could be accomplished via social engineering, brute force password guessing, or abuse or legitimate credentials. XSS affects only pages that users with 'view all downloads count' permission can access (such as site admins).

Proof of Concept:

  1. Install Drupal and Download Count module
  2. Navigate to the Download counter admin page at ?q=admin/settings/download_count
  3. Enter "<script>alert('xss1');</script>" in the 'Title' field
  4. Enter "<script>alert('xss2');</script>" in the 'Header' field
  5. Enter "<script>alert('xss3');</script>" in the 'Footer' field
  6. Save the form
  7. View rendered JavaScript at ?q=download_counter

NB: If the 'Input Format' radio button is set to 'Filtered HTML' in the configuration screen only the 'Title' field is vulnerable.

Vendor Response:

"Disable the Download Count module and remove the module from your filesystem." Ref http://drupal.org/node/1196670

Patch:

Applying the following patches mitigates these issues in version 6.x-1.5

--- download_count/download_count.module	2010-05-30 15:40:04.000000000 -0400
+++ download_count/download_count.module	2011-04-04 14:17:43.503554109 -0400
@@ -121,7 +121,7 @@ function download_count_admin_settings()
 }
 function download_count_view_page() {
   global $user;
-  drupal_set_title(variable_get('download_counter_view_page_title', t('Download counter')));
+  drupal_set_title(check_plain(variable_get('download_counter_view_page_title', t('Download counter'))));
   $header[] = array('data' => t('filename'), 'field' => 'filename');
   $header[] = array('data' => t('hits'), 'field' => 'count', 'sort' => 'desc');
   $header[] = array('data' => t('last download'), 'field' => 'timestamp');
@@ -145,9 +145,9 @@ function download_count_view_page() {
   if (empty($rows)) {
     $rows[] = array(array('data' => t('No file attachment has been downloaded.'), 'colspan' => '4'));
   }
-  $output = check_markup(variable_get('download_counter_view_page_header', ''), variable_get('download_counter_view_page_format', 0), false);
+  $output = check_markup(check_plain(variable_get('download_counter_view_page_header', '')), variable_get('download_counter_view_page_format', 0), false);
   $output .= theme('table', $header, $rows, array('class' => 'download_count'));
-  $output .= check_markup(variable_get('download_counter_view_page_footer', ''), variable_get('download_counter_view_page_format', 0), false);
+  $output .= check_markup(check_plain(variable_get('download_counter_view_page_footer', '')), variable_get('download_counter_view_page_format', 0), false);
   return $output;
 }
 /**