GNT sans publicité, site mobile, fonctionnalitées exclusives...

[PHP] XSS, charsets et htmlentities()

Le
John GALLET
Bonjour,

[xpost fr.comp.securite fu2 fr.comp.lang.php, tous les deux modérés]


Au cours d'une discussion récente, certains contributeurs m'ont fait
remarqué la "faille" PHP suivante, dont j'ignorais totalement l'existence :

http://shiflett.org/archive/178

Etant de nature "Saint Thomas", j'essaie donc de reproduire dans un cas
réaliste l'attaque en question, surtout que ça permet toujours de mieux
comprendre ce qui se passe.

Or, je n'arrive absolument pas à reproduire cette "faille" dans une
autre configuration qu'un charset UTF-7, ce qui n'est en rien une faille
mais simplement lié au fait que htmlentities ne reconnait pas ce
charset, et c'est clairement spécifié dans le manuel:
http://fr2.php.net/manual/en/functi...tities.php

Voici les tests que j'ai effectués :

1) le script de réception, dont on teste la vulnérabilité. J'ai
magic_quotes_gpc activées, d'où le stripslashes parce que sinon le code
JS se fait sabrer de toutes façons.

recep.php

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-7">
<title>test</title>
</head>
<body>
<?php
echo "XSS me !<BR>".htmlentities(stripslashes($_REQUEST['var']));
?>
</body>
</html>


2) le stimulateur

<?php
dl('mbstring.so'); // je n'ai pas la lib en standard, dynamic load.
define ('ATTACK_URL','http://www.mabecane.tld/recep.php');
$string = "<script>alert('Pouet');</script>";
$string = mb_convert_encoding($string, 'UTF-7');
$data=array('var'=>$string);

// on donne l'URL du service.
$ch = curl_init(ATTACK_URL);

// login/pass si le répertoire est protégé par un .htaccess
// curl_setopt($ch,CURLOPT_USERPWD,"monlogin:monpass");

// on souhaite contrôler le retour nous même dans le cas général.
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
// on se fait le luxe d'envoyer les données par POST
curl_setopt($ch, CURLOPT_POST, 1);
// On n'envoie pas de headers particuliers
curl_setopt($ch, CURLOPT_HEADER, 0);
// on remplit ici les données à poster
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
// on appelle la page distante, exactement comme un navigateur
// et $str contient le retour généré.
$str=curl_exec($ch);
curl_close($ch);
// on pourrait tripatouiller $str si on le souhaitait
echo $str;
?>

On appelle ensuite le stimulateur ou par php -f ou par navigateur.
Tests effectués avec un netscape/mozilla quelconque sur linux.
Si je laisse UTF-7 comme charset, en effet, il y a bien affichage de la
pop-up JS. En essayant au hasard n'importe quoi d'autre comme charset
cité dans le man de htmlentities, et sans jamais spécifier de charset
comme 3eme paramètre de htmlentities( ), en mettant des charsets
différents ou identiques dans le stimulateur et le script de réception,
j'ai des zigouigouis, l'affichage html du code JS, mais jamais la
pop-up. Si je supprime l'appel à htmlentities(), la XSS a bien lieu.

Etant particulièrement nul en compréhension des charsets (ça m'a
toujours brouté) j'en conclue donc que j'ai dû passer à côté de quelque
chose, mais quoi ? Ca ne marche pas mieux en faisant un formulaire à la
place d'un appel à curl, même en forçant le accept-charset dans FORM.

JG
Lire les 14 réponses

Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 3
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Olivier Miakinen
Le #122253

http://shiflett.org/archive/178

Etant de nature "Saint Thomas", j'essaie donc de reproduire dans un cas
réaliste l'attaque en question, surtout que ça permet toujours de mieux
comprendre ce qui se passe.

Or, je n'arrive absolument pas à reproduire cette "faille" dans une
autre configuration qu'un charset UTF-7, ce qui n'est en rien une faille
mais simplement lié au fait que htmlentities ne reconnait pas ce
charset, et c'est clairement spécifié dans le manuel:
http://fr2.php.net/manual/en/functi...tities.php


Je répondrai plus loin.

Voici les tests que j'ai effectués :

[...]
echo "XSS me ! [...]

2) le stimulateur

[...]
$string = "<script>alert('Pouet');</script>";
$string = mb_convert_encoding($string, 'UTF-7');


J'ai utilisé ceci pour faire la conversion en ligne :

Résultat :
$string = "+ADw-script+AD4-alert('Pouet')+ADsAPA-/script+AD4-";

Pas étonnant que htmlentities ne voie pas les « < » et « > » !

[...]
Tests effectués avec un netscape/mozilla quelconque sur linux.


... avec la configuration par défaut concernant les encodages, je suppose.

Si je laisse UTF-7 comme charset, en effet, il y a bien affichage de la
pop-up JS. En essayant au hasard n'importe quoi d'autre comme charset
cité dans le man de htmlentities, et sans jamais spécifier de charset
comme 3eme paramètre de htmlentities( ), en mettant des charsets
différents ou identiques dans le stimulateur et le script de réception,
j'ai des zigouigouis, l'affichage html du code JS, mais jamais la
pop-up. Si je supprime l'appel à htmlentities(), la XSS a bien lieu.


Normal tant que le navigateur ne « devine » pas que c'est de l'UTF-7.

Etant particulièrement nul en compréhension des charsets (ça m'a
toujours brouté) j'en conclus donc que j'ai dû passer à côté de quelque
chose, mais quoi ?


Ce à côté de quoi tu es passé, c'est « Internet Explorer makes this
assumption automatically » : en l'absence de charset explicite, IE
essaye de deviner, et la présence des +Axx- lui permet de réussir assez
facilement.

Note que, même si ce n'est pas le comportement par défaut de Mozilla ni
de Firefox, on conseille souvent dans fciw.navigateurs de le configurer
pour qu'il le fasse aussi. Tu peux essayer toi-même : menu « Affichage »
(View en anglais), sous-menu « Encodage des caractères », « Détection
automatique », « Universel ».


Un dernier point : si ça ne marche toujours pas, c'est peut-être que tu
as correctement configuré ton serveur, de telle sorte qu'il envoie
lui-même un charset par défaut dans les entêtes HTTP (bien évidemment
différent de UTF-7).

Cordialement,
--
Olivier Miakinen

ftc
Le #122251
1) le script de réception, dont on teste la vulnérabilité. J'ai
magic_quotes_gpc activées, d'où le stripslashes parce que sinon le code
JS se fait sabrer de toutes façons.


On pourrait remplacer par :

ftc
Le #122252
Or, je n'arrive absolument pas à reproduire cette "faille" dans une
autre configuration qu'un charset UTF-7, ce qui n'est en rien une faille
mais simplement lié au fait que htmlentities ne reconnait pas ce
charset, et c'est clairement spécifié dans le manuel:
http://fr2.php.net/manual/en/functi...tities.php

Voici les tests que j'ai effectués :
[SNIP]


On appelle ensuite le stimulateur ou par php -f ou par navigateur.
Tests effectués avec un netscape/mozilla quelconque sur linux.
Si je laisse UTF-7 comme charset, en effet, il y a bien affichage de la
pop-up JS. En essayant au hasard n'importe quoi d'autre comme charset
cité dans le man de htmlentities, et sans jamais spécifier de charset
comme 3eme paramètre de htmlentities( ), en mettant des charsets
différents ou identiques dans le stimulateur et le script de réception,
j'ai des zigouigouis, l'affichage html du code JS, mais jamais la
pop-up. Si je supprime l'appel à htmlentities(), la XSS a bien lieu.


Tu n'as pas regardé l'exposé du problème dans son intégralité. C'est
vrai que ce n'est pas directement une faille liée à PHP, c'est plutôt
une utilisation inappropriée de htmlentities et une faille de IE.

Le problème arrive dans deux circonstances :

1) le charset n'est spéciifé ni par le serveur ni dans la page de
destination, le navigateur va donc en déduire dans certaines conditions
( avec son système de détection automatique de charset ) que c'est une
page en UTF-7.

2) Le code UTF-7 est placé dans les 4096 premiers octets de la page,
dans ce cas, il semblerait que IE interprète la page comme étant du
UTF-7 malgré les charsets indiqués ( la faille a peut être été corrigée
depuis sur IE )

A noter que ce n'est pas spécifique à PHP, la faille a été à l'origine
mise en évidence sur Google.

John Gallet
Le #122247
Re,


.... avec la configuration par défaut concernant les encodages, je suppose.
Avec rien de tripoté, donc probablement par défaut.


Normal tant que le navigateur ne « devine » pas que c'est de l'UTF-7.
C'est bien pour ça que j'avais précisé :

<meta http-equiv="Content-Type" content="text/html; charset=utf-7">
Ca ne suffit pas ? (si la réponse est "non, suffit pas", la question
suivante sera "alors à quoi ça sert ?")

Ce à côté de quoi tu es passé, c'est « Internet Explorer makes this
assumption automatically » : en l'absence de charset explicite, IE
essaye de deviner, et la présence des +Axx- lui permet de réussir assez
facilement.
Déjà, en test sous IE, si j'enlève la ligne :

header('Content-Type: text/html; charset=UTF-7');
alors ça m'affiche seulement les zigouigouis que tu as écris. Donc je ne
sais pas ce qu'il détecte soit disant automatiquement, mais pas la xss.
Test fait sous un XP pro SP2 patché au max en automatique.
Ensuite, j'ai refait les tests aujourd'hui sous IE, même combat.

Un dernier point : si ça ne marche toujours pas, c'est peut-être que tu
as correctement configuré ton serveur, de telle sorte qu'il envoie
lui-même un charset par défaut dans les entêtes HTTP (bien évidemment
différent de UTF-7).
Ce serait bien à l'insu de mon plein gré si tel était le cas.



JG

John Gallet
Le #122248
Bonjour,

Tu n'as pas regardé l'exposé du problème dans son intégralité.
C'est possible. Moi je dis sur fclphp que htmlentities suffit pour

éviter les XSS, on me répond "non, cf le lien schmoll", ledit lien
schmoll n'explique rien et donc j'essaie de comprendre où est le
problème pour ne pas avoir l'impression d'être à l'abri des attaques
alors que la terre entière rigole dans mon dos.

vrai que ce n'est pas directement une faille liée à PHP, c'est plutôt
une utilisation inappropriée de htmlentities et une faille de IE.
Soit, mais je ne comprends toujours pas ce que htmlentities vient faire

là dedans.

1) le charset n'est spéciifé ni par le serveur ni dans la page de
destination,
Bon, donc je vire dans mon recep.php la spécification explicite du charset.


le navigateur va donc en déduire dans certaines conditions
( avec son système de détection automatique de charset ) que c'est une
page en UTF-7.
Pas chez moi sur I.E 6.0.2900.etc sous xp pro en sp2. Si je supprime la

définition explicite du charset dans le meta, j'obtiens les caractères à
la con. Je n'ai rien fait de spécial dans la configuration d'IE ou de la
machine windows en question, j'en suis bien incapable.

2) Le code UTF-7 est placé dans les 4096 premiers octets de la page,
Voici ce que je reçois :


<html lang="en">
<head>
<title>a</title>
</head>
<body>
XSS me !<BR>+ADw-script+AD4-alert('Pouet')+ADsAPA-/script+AD4-</body>
</html>

Ca doit faire moins de 4096 .

dans ce cas, il semblerait que IE interprète la page comme étant du
UTF-7 malgré les charsets indiqués ( la faille a peut être été corrigée
depuis sur IE )
Ca, c'est bien possible. Mais alors donc ce n'est pas lié à

htmlentities(), c'est un problème de navigateur.

A noter que ce n'est pas spécifique à PHP, la faille a été à l'origine
mise en évidence sur Google.


Bon, donc on en conclue quoi concrètement sur ce qu'il faut faire en PHP
et surtout sur le rôle ou l'appel de htmlentities( ) ? Moi j'en
concluerais bien qu'il faut spécifier explicitement le charset utilisé
dans les pages HTML (c'est pas un scoop, mais autant le vérifier) et que
htmlentities n'a **RIEN** à voir là dedans, ai-je tord ?

JG

Publicité
Suivre les réponses
Poster une réponse
Anonyme