Friday, 10 July 2009 10:34

The Joomla component uddeIM is vulnerable to XSS injection in its BBCode implementation. Extra CSS parameters can be passed inside the [color] tag, and Internet Explorer versions before 8 will run scripts using the 'expression()' CSS function.

[color=#ff0000;font-size:expression(document.write(String.fromCharCode(88,83,83)))]XSS[/color]

For this XSS to work, the site must allow at least font formatting BBCode and the victim must be running a vulnerable browser.

Stephan Slabihoud sent me this patched bbparser.php, which seems to fix the issue:

<?php
// ********************************************************************************************
// Title          udde Instant Messages (uddeIM)
// Description    Instant Messages System for Mambo 4.5 / Joomla 1.0 / Joomla 1.5
// Author         © 2007-2008 Stephan Slabihoud, © 2006 Benjamin Zweifel
// License        This is free software and you may redistribute it under the GPL.
//                uddeIM comes with absolutely no warranty.
//                Use at your own risk. For details, see the license at
//                http://www.gnu.org/licenses/gpl.txt
//                Other licenses can be found in LICENSES folder.
//                Redistributing this file is only allowed when keeping the header unchanged.
// ********************************************************************************************
//                This code uses portions of the bbcode script from phpBB (C) 2001 The phpBB Group
// ********************************************************************************************
 
if (!(defined('_JEXEC') || defined('_VALID_MOS'))) { die( 'Direct Access to this location is not allowed.' ); }
 
function uddeIMbbcode_replace($string, $config) {
 
  if($config->allowbb > 0) {
 
    // replace font formatting [b] [i] [u] [color= [size=
    // bold
      $string = preg_replace("/(\[b\])(.*?)(\[\/b\])/si","<span style=\"font-weight: bold\">\\2</span>",$string);
 
    // underline
      $string = preg_replace("/(\[u\])(.*?)(\[\/u\])/si","<span style=\"text-decoration: underline\">\\2</span>",$string);
 
    // italic
    $string = preg_replace("/(\[i\])(.*?)(\[\/i\])/si","<span style=\"font-style: italic\">\\2</span>",$string);
 
    // max size is 7
    $string = preg_replace("/\[size=([1-7])\](.+?)\[\/size\]/si","<font size=\\1\">\\2</font>",$string);
 
    // color
    $string = preg_replace("%\[color=#(.{1,6}?)\](.*?)\[/color\]%si","<span style=\"color: #\\1\">\\2</span>",$string);
 
    // more font formatters opened than closed
//    do {
//      $string.="</span>";
      // close them
//    } while (substr_count($string,"<span") > substr_count($string,"</span>"));
    while (substr_count($string,"<span") > substr_count($string,"</span>")) {
      $string.="</span>";
    }
 
    // more font formatters closed than opened (less likely case)  
//    do {
//      $string="<span>".$string;
      // add a dummy container to balance that out
//    } while (substr_count($string,"<span") < substr_count($string,"</span>"));
    while (substr_count($string,"<span") < substr_count($string,"</span>")) {
      $string="<span>".$string;
    }
  }
 
  if($config->allowbb > 1) {
 
    // http, https, ftp, mailto
    $passes = Array();
    $passes[] = "url";
    $passes[] = "topurl";
 
    foreach ($passes as $pass) {
      $string=str_replace("[".$pass."=index.php", "#*#LINK".$pass."INDEX=#*#", $string);
      $string=str_replace("[".$pass."=http://", "#*#LINK".$pass."HTTP=#*#", $string);
      $string=str_replace("[".$pass."=ftp://", "#*#LINK".$pass."FTP=#*#", $string);
      $string=str_replace("[".$pass."=https://", "#*#LINK".$pass."HTTPS=#*#", $string);
      $string=str_replace("[".$pass."=mailto:", "#*#LINK".$pass."MAILTO=#*#", $string);  
 
      $string=str_replace("[".$pass."]index.php", "#*#LINK".$pass."INDEX]#*#", $string);    
      $string=str_replace("[".$pass."]http://", "#*#LINK".$pass."HTTP]#*#", $string);
      $string=str_replace("[".$pass."]ftp://", "#*#LINK".$pass."FTP]#*#", $string);
      $string=str_replace("[".$pass."]https://", "#*#LINK".$pass."HTTPS]#*#", $string);
      $string=str_replace("[".$pass."]mailto:", "#*#LINK".$pass."MAILTO]#*#", $string);        
 
      $string=str_replace("[".$pass."]", "[".$pass."]http://", $string);
      $string=str_replace("[".$pass."=", "[".$pass."=http://", $string);
 
      $string=str_replace("#*#LINK".$pass."HTTP=#*#", "[".$pass."=http://", $string);
      $string=str_replace("#*#LINK".$pass."FTP=#*#", "[".$pass."=ftp://", $string);
      $string=str_replace("#*#LINK".$pass."HTTPS=#*#", "[".$pass."=https://", $string);
      $string=str_replace("#*#LINK".$pass."MAILTO=#*#", "[".$pass."=mailto:", $string);      
      $string=str_replace("#*#LINK".$pass."INDEX=#*#", "[".$pass."=index.php", $string);      
 
      $string=str_replace("#*#LINK".$pass."HTTP]#*#", "[".$pass."]http://", $string);
      $string=str_replace("#*#LINK".$pass."FTP]#*#", "[".$pass."]ftp://", $string);
      $string=str_replace("#*#LINK".$pass."HTTPS]#*#", "[".$pass."]https://", $string);
      $string=str_replace("#*#LINK".$pass."MAILTO]#*#", "[".$pass."]mailto:", $string);
      $string=str_replace("#*#LINK".$pass."INDEX]#*#", "[".$pass."]index.php", $string);    
    }
 
    $string = preg_replace("/\[img size=([0-9][0-9][0-9])\](http\:\/\/.*?)\[\/img\]/si","[#*#img size=$1]$2[/#*#img]",$string);
    $string = preg_replace("/\[img size=([0-9][0-9])\](http\:\/\/.*?)\[\/img\]/si","[#*#img size=$1]$2[/#*#img]",$string);
    $string = preg_replace("/\[img\](http\:\/\/.*?)\[\/img\]/si","[#*#img]$1[/#*#img]",$string);
 
    $string = preg_replace("/\[img size=([0-9][0-9][0-9])\](.*?)\[\/img\]/si","[img size=$1]http://$2[/img]",$string);
    $string = preg_replace("/\[img size=([0-9][0-9])\](.*?)\[\/img\]/si","[img size=$1]http://$2[/img]",$string);
    $string = preg_replace("/\[img\](.*?)\[\/img\]/si","[img]http://$1[/img]",$string);
 
    $string = str_replace("[#*#img", "[img", $string);
    $string = str_replace("[/#*#img", "[/img", $string);
 
    // ul li replacements
        $string = preg_replace("/(\[ul\])(.*?)(\[\/ul\])/si","<ul>\\2</ul>",$string);
        $string = preg_replace("/(\[ol\])(.*?)(\[\/ol\])/si","<ol type=1>\\2</ol>",$string);
        $string = preg_replace("/(\[li\])(.*?)(\[\/li\])/si","<li>\\2</li>",$string);
 
        // make regular HTML URL links targets _blank, bbCode URL translation
    // this is very bad: since when we have two links (a link without comprofiler and a link with comprofiler) this matches both
    // but it is even worse when we do not remove javascript links...
        $string = preg_replace('/\[(top)?url\](.*?)javascript(.*?)\[\/\\1url\]/si','<span style=\'text-decoration: line-through\'>javascript link</span>',$string);
        $string = preg_replace('/\[(top)?url=(.*?)javascript(.*?)\](.*?)\[\/\\1url\]/si','<span style=\'text-decoration: line-through\'>javascript link</span>',$string);
 
    // if comprofiler in link, make link to top instead of blank
    // this is very bad: since when we have two links (a link without comprofiler and a link with comprofiler) this matches both
    // $string = preg_replace("/\[url\](.*?)comprofiler(.*?)\[\/url\]/si","<a href=\\1comprofiler\\2 target=\"_top\">\\1comprofiler\\2</a>",$string);
    // $string = preg_replace("/\[url=(.*?)comprofiler(.*?)\](.*?)\[\/url\]/si","<a href=\"\\1comprofiler\\2\" target=\"_top\">\\3</a>",$string);  
 
    // now the rest of the links to blank
        $string = preg_replace("/\[url\](.*?)\[\/url\]/si", "<a href=\"\\1\" target=\"_blank\">\\1</a>", $string);
        $string = preg_replace("/\[url=(.*?)\](.*?)\[\/url\]/si", "<a href=\"\\1\" target=\"_blank\">\\2</a>", $string);  
        $string = preg_replace("/\[topurl\](.*?)\[\/topurl\]/si", "<a href=\"\\1\">\\1</a>", $string);
        $string = preg_replace("/\[topurl=(.*?)\](.*?)\[\/topurl\]/si", "<a href=\"\\1\">\\2</a>", $string);  
 
    // img replacement
        $string = preg_replace("/\[img size=([0-9][0-9][0-9])\](.*?)\[\/img\]/si", "<img src=\"$2\" border=\"0\" width=\"$1\" />", $string);
        $string = preg_replace("/\[img size=([0-9][0-9])\](.*?)\[\/img\]/si", "<img src=\"$2\" border=\"0\" width=\"$1\" />", $string);
        $string = preg_replace("/\[img\](.*?)\[\/img\]/si", "<img src=\"$1\" border=\"0\" />", $string);
        $string = preg_replace("/<img(.*?)javascript(.*?)>/si", '<span style=\'text-decoration: line-through\'>javascript link</span>', $string);  
 
  }
 
  return $string;
 
}
 
function uddeIMsmile_replace($string, $config) {  
  $pathtouser  = uddeIMgetPath('user');
  $pathtosite  = uddeIMgetPath('live_site');
 
  // now replace smilies if that option is turned on 
  // Use Joomlaboard smilies if that is installed, otherwise uddeim's
 
  $iconfolder="images";
  if ($config->animated) {
    $iconfolder="animated"; }
 
  $message_emoticons=array(
      ":))"        => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_laughing.gif"  alt="" border="0" align="middle" />',    
    ":D"         => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_laughing.gif"  alt="" border="0" align="middle" />',    
      ":*"         => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_heart.gif"     alt="" border="0" align="middle" />',
      ":?"         => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_wondering.gif" alt="" border="0" align="middle" />',
      ":x"         => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_crossed.gif"   alt="" border="0" align="middle" />',
      "B)"         => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_cool.gif"      alt="" border="0" align="middle" />',
      ":("         => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_sad.gif"       alt="" border="0" align="middle" />',
      ":)"         => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_smile.gif"     alt="" border="0" align="middle" />',
      ":-("        => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_sad.gif"       alt="" border="0" align="middle" />',
      ":-)"        => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_smile.gif"     alt="" border="0" align="middle" />',
      ":laugh:"    => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_laughing.gif"  alt="" border="0" align="middle" />',
      ":grin:"     => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_laughing.gif"  alt="" border="0" align="middle" />',
      ";)"         => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_wink.gif"      alt="" border="0" align="middle" />',
      ";-)"        => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_wink.gif"      alt="" border="0" align="middle" />',
      ":P"         => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_tongue.gif"    alt="" border="0" align="middle" />',
      ":mad:"      => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_angry.gif"     alt="" border="0" align="middle" />',
      ":angry:"    => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_angry.gif"     alt="" border="0" align="middle" />',
      ":ohmy:"     => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_shocked.gif"   alt="" border="0" align="middle" />',
    ":o"         => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_shocked.gif"   alt="" border="0" align="middle" />',
      ":shock:"    => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_shocked.gif"   alt="" border="0" align="middle" />',
      ":blush:"    => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_blush.gif"     alt="" border="0" align="middle" />',
      ":kiss:"     => '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/emoticon_kiss.gif"      alt="" border="0" align="middle" />',
      );
 
  if ($config->animatedex) { 
    $iconfolder="animated-extended";
    $smileys = $pathtouser."/templates/".$config->templatedir."/".$iconfolder."/";
    if (is_dir($smileys)) {
      $folder=opendir ($smileys); 
      while ($file = readdir ($folder)) {
        if($file != "." && $file != ".." && (substr($file, strrpos($file, '.'))=='.gif')) {
          $ext = strrchr($file, '.');
          if($ext !== false) {
            $noextname = substr($file, 0, -strlen($ext));
          } else {
            $noextname = $file;
          }
          $name = ":".$noextname.":";
          $message_emoticons[$name] = '<img src="'.$pathtosite.'/components/com_uddeim/templates/'.$config->templatedir.'/'.$iconfolder.'/'.$noextname.'.gif" alt="" border="0" align="middle" />';
        }
      }
      closedir($folder);
    }
  }
 
  reset($message_emoticons);
  while (list($emo_txt,$emo_src)=each($message_emoticons)) {
    $string=str_replace($emo_txt,$emo_src,$string);
  }
  return $string;
}
 
function uddeIMbbcode_strip($string) {
 
  // bold
    $string = preg_replace("/(\[b\])(.*?)(\[\/b\])/si", "\\2", $string);
 
  // underline
    $string = preg_replace("/(\[u\])(.*?)(\[\/u\])/si", "\\2", $string);
 
  // italic
  $string = preg_replace("/(\[i\])(.*?)(\[\/i\])/si", "\\2", $string);
 
  // size Max size is 7
  $string = preg_replace("/\[size=([1-7])\](.+?)\[\/size\]/si", "\\2", $string);
 
  // color
  $string = preg_replace("%\[color=(.*?)\](.*?)\[/color\]%si", "\\2", $string);
 
  // ul li replacements
  $string = preg_replace("/(\[ul\])(.*?)(\[\/ul\])/si", "\\2", $string);
  $string = preg_replace("/(\[ol\])(.*?)(\[\/ol\])/si", "\\2", $string);
  $string = preg_replace("/(\[li\])(.*?)(\[\/li\])/si", "\\2\\n", $string);
 
  // sanitize javascript
  $string = preg_replace("/\[(top)?url\](.*?)javascript(.*?)\[\/\\1url\]/si", "", $string);
  $string = preg_replace("/\[(top)?url=(.*?)javascript(.*?)\](.*?)\[\/\\1url\]/si", "", $string);
 
  // convert urls
  $string = preg_replace("/\[(top)?url\](.*?)\[\/\\1url\]/si", "\\2", $string);
  $string = preg_replace("/\[(top)?url=(.*?)\](.*?)\[\/\\1url\]/si", "\\3 (\\2)", $string);  
 
  // only front tag present
  $string = preg_replace("/\[(top)?url=(.*?)\]/si","",$string);  
 
  // img replacement
  $string = preg_replace("/\[img size=([0-9][0-9][0-9])\](.*?)\[\/img\]/si", "", $string);
  $string = preg_replace("/\[img size=([0-9][0-9])\](.*?)\[\/img\]/si", "", $string);
  $string = preg_replace("/\[img\](.*?)\[\/img\]/si", "", $string);
  $string = preg_replace("/<img(.*?)javascript(.*?)>/si", '', $string);  
 
  // only front tag present
  $string = preg_replace("/\[img size=([0-9][0-9][0-9])\]]/si", "", $string);
  $string = preg_replace("/\[img size=([0-9][0-9])\]]/si", "", $string);
 
  // cut remaining single tags
  $string = str_replace("[i]", "", $string);
  $string = str_replace("[/i]", "", $string);
  $string = str_replace("[b]", "", $string);
  $string = str_replace("[/b]", "", $string);
  $string = str_replace("[u]", "", $string);
  $string = str_replace("[/u]", "", $string);
  $string = str_replace("[ul]", "", $string);
  $string = str_replace("[/ul]", "", $string);
  $string = str_replace("[ol]", "", $string);
  $string = str_replace("[/ol]", "", $string);
  $string = str_replace("[li]", "", $string);
  $string = str_replace("[/li]", "", $string);
 
    $string = preg_replace("/\[(top)?url=(.*?)javascript(.*?)\]/si", "", $string);  
    $string = preg_replace("/\[img size=([0-9][0-9][0-9])\]/si", "", $string);
    $string = preg_replace("/\[img size=([0-9][0-9])\]/si", "", $string);
    $string = preg_replace("/\[size=([1-7])\]/si", "", $string);
    $string = preg_replace("/\[color=(.*?)\]/si", "", $string);
    $string = preg_replace("/\[(top)?url\]/si", "", $string);  
    $string = preg_replace("/\[\/(top)?url\]/si", "", $string);  
  $string = str_replace("[img]", "", $string);
  $string = str_replace("[/img]", "", $string);
  $string = str_replace("[/color]", "", $string);
  $string = str_replace("[/size]", "", $string);    
 
  return $string;
}
Last Updated on Friday, 10 July 2009 10:42
 

Add your comment

Your name:
Comment:
  The word for verification. Lowercase letters only with no spaces.
Word verification:

The Joomla!® name is used under a limited license from Open Source Matters in the United States and other countries. Jeff Channell is not affiliated with or endorsed by Open Source Matters or the Joomla!® Project.

Santorum
Joomla Extensions