mars
2007
Il n’est pas rare de voir trainer sur le web, des formulaires de ce style là :
A: webmaster@monsite.com
De: <input type="text" name="expediteur">
Sujet : <input type="text" name="sujet">
Message : <textarea name="message" rows="10" cols="60" lines="20"></textarea>
<input type="submit" name="send" value="Envoyer">
</form>
// mailing.php :
$to="webmaster@monsite.com";
$from=$_POST["expediteur"];
if (mail($to,$_POST["sujet"],$_POST["message"],"From: $from\n")){
echo "Votre mail a bien été envoyé à $to";
}else{
echo "Votre mail n'a pas pu être envoyé.";
}
?>
Et bien ce code est largement ouvert au spamming email
D’autant plus que les webmasters ont tendance à appeler ces fichiers « mail.php », ou « contact.php », ce qui est facilement trouvable sur google, ou google code search.
Un code comme celui ci, de même que beaucoup d’autres dans le style, présente une faille de sécurité, qui va permettre à une personne malveillante, d’envoyer à répétition des emails, totalement personnalisés, via VOTRE serveur mail.
Quand on envoie un mail en PHP, le destinataire reçoit un mail dont l’ip de l’expéditeur est celui du site depuis lequel la fonction mail() a été appelée. Le site fait donc usage de proxy SMTP.
Rappel : La fonction mail fonctionne comme ceci : mail([DESTINATAIRE],[SUJET],[MESSAGE],[HEADERS]);
On peut détourner la fonction en injectant du code dans le champ expéditeur (From:). On choisira From: comme cible, car il apparait après les en-tête Subject: et To:, il fait parti des headers ajoutés manuellement au mail et n’est pas protégé par mail() et la RFC.
Notez bien que même si le champ destinataire est fixé, le fait de pouvoir remplir le champ expéditeur, suffit pour une injection.
Inutile de parler donc du cas où tous les arguments de la fonction mail() sont définissables par l’utilisateur.
Il est plus intéressant d’imaginer comment détourner la fonction mail() quand il y a certaines restrictions; et notamment quand le code du destinataire est déja définit ( « contactez le webmaster », par exemple ), ce qui est très courant.
On ne peut donc pas choisir le destinataire via le premier argument de la fonction mail(), vu qu’il est définit dans le script, par contre on peut définir le sujet, le message, et l’expéditeur.
Rappelons le format d’envoi de mail texte( non MIME ) en PHP, pour une fonction de type mail($destinataire,$sujet,$message,$headers); selon la RFC 2822 :
To: $destinataire
Subject: $sujet
$headers$message
Donc quand on fait un appel à la fonction mail(« webmaster@monsite.com », »coucou », »Salut,\n voici un pti message », »From: quelquun@unsite.com »); on envoie :
To: webmaster@monsite.com
Subject: coucou
From: quelquun@unsite.comSalut,
voici un pti message
Nous allons tenter de modifier ou d’ajouter d’autres headers que le « From: ».
Injecter des headers (en-têtes), permet de détourner la fonction principale du script, et envoyer un email anonyme à quelqu’un d’autre que le webmaster du site ( dans notre exemple )
On peut faire du spamming, ou du vol d’identité, en faisant croire que le mail a été envoyé par quelqu’un d’arbitraire.
C’est possible en utilisant par exemple l’header « Cc » ( Carbon Copy ), qui envoie une copie conforme du mail aux personnes indiquées en argument; Ou mieux encore, le header « Bcc » (Blind Carbon Copy) qui envoie lui une copie conforme sans qu’aucun autre destinataire ne soit au courant.
La RFC spécifie que pour définir un nouvel header, il faut passer à la ligne, et cela est rendu possible grâce au caractère <LF> (Line Feed), dont la valeur hexadécimale est 0x0A.
Ainsi, en reprenant l’exemple de script PHP ci-dessus, si je donne comme valeur :
From: (expediteur) -> « myemail@anonyme.com%0ACc:email1@site1.com%0ABcc:email2@site2.com,email3@site3.com »
Subject: (sujet) -> « Ceci est mon sujet »
(message) -> « Un message »
alors l’email envoyé sera de la forme :
To: webmaster@monsite.com
Subject: Ceci est mon sujet
From: myemail@anonymous.com
Cc:email1@site1.com
Bcc:email2@site2.com,email3@site3.comUn message
et on aura non seulement bel et bien injecté des headers, vu que le seul prévu par le webmaster était « From », mais on a en plus envoyé l’email à trois personne de notre choix alors qu’on était pas sensé pouvoir choisir de destinataire.
On a utilisé les headers « Cc » et « Bcc » pour envoyer notre mail à qui on voulait, mais il est de même possible de redéfinir le header « To: », la nouvelle valeur viendra juste s’ajouter à l’ancienne, comme si on avait séparé les deux mails par des virgules.
Ainsi : donnons à l’expéditeur la valeur : « myemail@anonyme.com%0ATo:boiteemail@domaine.com » :
To: webmaster@monsite.com
Subject: Ceci est mon sujet
From: myemail@anonyme.com
To:boiteemail@domaine.comUn message
La répétition du « To » ne posera pas de problème, et l’email sera envoyé à webmaster@monsite.com ET boiteemail@domaine.com .
Idem pour le sujet, on peut redéfinir le header ‘Subject:’ , le sujet sera alors la concaténation de tous les sujets définis par cet en-tête.
Pour le cors du message, pas d’en-tête spécifique, si on passe à la ligne avec un LF sans avoir définit d’en-tête , alors le corps du message commence.
Les corps de message seront concaténés, mais il est possible de faire carrément disparaitre un corps de message déja fixé dans le code PHP.
Changeons d’exemple, imaginons que nous ne puissions pas écrire de corps de message, mais que seuls To: et From: nous sont accessibles.
Dans ce cas, l’injection d’un en-tête « content-type=multipart/mixed » va nous permettre de faire disparaitre le corps du message initialement fixé.
Il va aussi nous permettre d’attacher des pièces jointes, ou d’écrire du HTML.
Je vous renvoie cette fois ci à la RFC2045, qui définit les normes concernant les emails MIME ( Multipurpose Internet Mail Extensions ).
Vous pouvez aussi vous renseigner sur le site GNU
Si on donne, via le formulaire web, une valeur à l’expediteur (From:) comme celle-ci : « onemail@onedomain.com%0AContent-Type:multipart/mixed;%20boundary=myBoundary;%0A–myBoundary%0AContent-Type:text/html%0A%0A<u>Un message souligné</u>%0A–myBoundary– »
L’email peut ressembler par exemple à ceci :
To: monami@sondomaine.com
Subject: Ce sujet est fixé par le webmaster du site, dans son formulaire
From: onemail@onedomaine.com
Content-Type: multipart/mixed; boundary= »MyBoundary »
–MyBoundary
Content-Type: text/html<u>Un message souligné</u>
–MyBoundary–
Voici ici le texte que le webmaster avait initialement fixé, dans son formulaire
Selon la RFC, la valeur de « boundary= » peut etre n’importe quoi. Le boundary est le séparateur qui va séparer les types contenu dans le multipart/mixed.
Avec –leBoundaryChoisit , on définit le début d’un nouveau type. C’est le boundary d’ouverture
Avec –leBoundaryChoisit– , on définit la fin du type en cours. C’est le boundary de fermeture
Et le fait est que tout ce qui se trouve après un boundary de fermeture, est tout simplement ignoré. Dans notre cas « Voici ici le texte que le webmaster avait initialement fixé, dans son formulaire » se trouve après –MyBoundary– , et est donc purement ignoré, et non affiché.
Nous avons donc envoyé à quelqu’un, un email au format html, alors que le webmaster s’attendait à un message fixe. Seul le sujet nous trahi ici. Mais celui ci n’est pas effacable totallement, il est juste complétable. Il faut savoir par contre que certains webmails n’afficheront que le dernier « Subject: » rencontré, celui injecté.
Bien, au niveau des solutions, il y en a plusieurs :
- Utiliser une classe non vulnérable à ce type d’attaque, telle que Zend_Mail par exemple
- Utiliser des patchs, comme le patch Suhosin
- Le mod Security d’Apache peut filtrer le contenu de $_POST et $_GET à la recherche de chaines telles que « Cc: » ou « Bcc: »
- Un filtrage php à base de preg_replace()
Pour plus d’infos, vous pouvez lire http://www.mailinjection.com
Un article parallèle sur les injections mail()
Commentaires récents
Archives
- novembre 2010
- août 2010
- juillet 2010
- juin 2010
- mai 2010
- avril 2010
- mars 2010
- février 2010
- janvier 2010
- décembre 2009
- novembre 2009
- octobre 2009
- septembre 2009
- août 2009
- juillet 2009
- juin 2009
- mai 2009
- avril 2009
- mars 2009
- février 2009
- janvier 2009
- décembre 2008
- novembre 2008
- octobre 2008
- septembre 2008
- août 2008
- juillet 2008
- juin 2008
- mai 2008
- avril 2008
- mars 2008
- février 2008
- janvier 2008
- décembre 2007
- novembre 2007
- octobre 2007
- septembre 2007
- août 2007
- juillet 2007
- juin 2007
- mai 2007
- avril 2007
- mars 2007
- février 2007