Exploiting the Drupal Suggest Terms Module

30 November -0001

The Drupal Suggested Terms module is a convenience module that helps a content producer by presenting a hyperlinked list of taxonomy terms that can be clicked to populate category vocabulary. However, in versions prior to 5.x-1.2 a cross site scripting (XSS) vulnerability exists. This vulnerability was announced on June 25, 2008 in SA-2008-039 and requires that a malicious user be able to create or edit content using the suggested terms module.

Installing Suggested Terms involves downloading the .tar.gz module code from http://drupal.org/project/suggestedterms and inflating it in your modules directory (note that in order for the exploit to work you need to download an older version of the code by clicking on the "View all releases" link). Next you must enable the module (Administer -> Site building -> Modules) . Finally you have to provide permissions to the module (Administer -> User management -> Access control). Once the module is installed you have to set up some category vocabulary (Administer -> Categories -> Add vocabulary) in order to actually use the module. For the purposes of this demonstration I created a vocabulary called "Vocab".

Once the module is properly installed you can begin to examine the vulnerability. By diff'ing the pre-patched version of suggested_terms.module with the patched version (5.x-1.2) you can spot the code changes that fix the vulnerability. Looking through he code you'll want to keep an eye out for variables included in output. You can quickly spot the change that fixes the XSS:

79c72
<     $terms[] = theme('suggestedterm', check_plain($record->name));
---
>     $terms[] = theme('suggestedterm', $record->name);

You can see the the patched version of the code includes a check_plain() call that sanitizes the $record->name variable. The check_plain() function actually appears in includes/bootstrap.inc and looks like:

function check_plain($text) {
  return drupal_validate_utf8($text) ? htmlspecialchars($text, ENT_QUOTES) : '';
}

You can see that the function utilizes the PHP function htmlspecialchars() with the optional ENT_QUOTES. This argument forces single quotes to be converted to their HTML ASCII equivelent ('). Utilizing this function will effectively fix a single quote escape. Because this function isn't called in the vulnerable version of the code we can see how HTML input could be used to inject JavaScript into the HTML presented to a user and introduce a XSS vulnerability.

Now that we know that the $record->name variable is vulnerable in the earlier versions of the module we can begin to develop some exploits. Let's look at the code presented to a user when we have a few suggested terms in the category "Vocab". When we edit content and view the source we see:

<input type="text" maxlength="255" name="taxonomy[tags][1]" id="edit-taxonomy-tags-1"  size="60" value="moderation, test, Test Moderation" class="form-text form-autocomplete" />
 <div class="description">Terms by name: <span class='suggestedterm'>moderation</span>, <span class='suggestedterm'>test</span>, <span class='suggestedterm'>Test Moderation</span></div>
 

You can clearly see that the suggested terms all show up nestled inside div tags. If we try to utilize a new suggested term, such as "hi<script>alert('foo');</script>" we can cause an alert to show up every time any Drupal user tries to create, or even edit, content.

Exploiting the Drupal suggested terms module

If you view the source code you can clearly see the injected JavaScript:

  <div class="description">Terms by name: <span class='suggestedterm'><script>alert('foo');</script></span>, <span class='suggestedterm'>moderation</span>, <span class='suggestedterm'>test</span>, <span class='suggestedterm'>Test Moderation</span></div>
 

Because any user that creates or edits content will be affected by this flaw, a lower privileged user could potentially use the XSS to affect an administrative account.