PHP - MAIL INJECTION

Un article de Wiki SOS-ADMIN.

Sommaire

[PHP] - MAIL INJECTION

Article basé sur différentes sources (voir les liens en dessous) ! [ article en cours de rédaction ]

Ce n'est pas une faille en soit, mais une utilisation non rigoureuse de la fonction mail de PHP qui peut conduire à l'envoi massif de mail SPAM. Commençons par le début:

La fonction mail s'utilise de la manière suivante:

mail(string destinataire, string sujet, string message [, string en-tête(s) additionnelle(s) [, string parametre(s) additionnel(s)]] )

Le formulaire de contact

Lorsque l'on crée un formulaire de contact sur un site, souvent pour éviter d'y laisser trainer une adresse email inutilement, on le fait souvent de la façon suivante (désolé pour les puristes, je simplifie le code du formulaire):

formulaire.html

 <form name="contact" method="POST" action="traitement.php">
    <input type="text" name="email" size="20" />
    <input type="text" name="sujet" size="50" />
    <textarea name="message" rows="15" cols="50"></textarea>
    <input type="submit" name="ok" value="Envoyer mon message" />
 </form>

Le code d'envoi du mail

Maintenant, regardons à un code d'envoi du mail.

traitement.php

 <?php
    $expediteur=$_POST['email'];
    $destinataire="destinataire@website.tld";
    if (mail($destinataire,$_POST['sujet'],$_POST['message'],"From: $expediteur\n"))
    {
      echo "Mail envoyé";
    }
    else
    {
      echo "Mail non envoyé";
    }
 ?>

Dangereux ce genre de formulaire ?

Vous vous dite: En quoi cela est-il dangereux ? Le destinataire est codé en dur !!!

Voyons ce que produit notre script:

 mail($destinataire,$_POST['sujet'],$_POST['message'],"From: $expediteur\n")

Donne +/- le résultat suivant :

 To: $destinataire
 Subject: $_POST['sujet']
 From: $expediteur
 -------------------
 $_POST['message']

Reprenons maintenant la syntaxe de la fonction mail:

 mail(string destinataire, string sujet, string message [, string en-tête(s) additionnelle(s) [, string parametre(s) additionnel(s)]] )

On se rend compte que le From est en fait placé dans les en-têtes additionnelles.

Et c'est là qu'est le problème ! Et non seulement pour un formulaire de contact, mais aussi pour les formulaires du genre "Envoyer cet article/page à un ami".

Car par le champ du formulaire qui permet au visiteur de rentrer son adresse email, il peut ajouter des en-têtes au message et donc ajouter/remplacer :

- un ou des destinataires;

- un nouveau sujet;

- un message;

- une pièce jointe.

Prenons quelques exemples qui montrent comment il est possible d'ajouter des en-têtes

Ajouter un destinataire ?

Le visiteur, qui veut se servir de votre formulaire de contact pour spammer, peut entrer la chaine suivante dans la case email du formulaire:

 spammeur@anonyme.tld%0ACc:adressespamee1@fai.tld%0ABcc:adressespamee2@fai.tld,adressespamee3@fai.tld

Cela enverra le mail avec le sujet et le message du spammeur, aussi bien à vous qu'aux 3 adresse spammées. Car il ajoute l'en-tête Cc: et Bcc:.

Cela donne dans les en-têtes du mail:

 To: $destinataire
 Subject: $_POST['sujet']
 From: spammeur@anonyme.tld
 Cc:adressespamee1@fai.tld
 Bcc:adressespamee2@fai.tld,adressespamee3@fai.tld
 -------------------
 $_POST['message']  

Maintenant, s'il entre ceci:

 spammeur@anonyme.tld%0ABcc:adressespamee1@fai.tld,adressespamee2@fai.tld,adressespamee3@fai.tld

Vous recevrez son mail, en destinataire principal, mais vous ne verrez pas qu'il a été envoyé.

 To: $destinataire
 Subject: $_POST['sujet']
 From: spammeur@anonyme.tld
 Bcc:adressespamee1@fai.tld,adressespamee2@fai.tld,adressespamee3@fai.tld
 -------------------
 $_POST['message']

Ajouter un nouveau sujet?

Il suffit simplement d'ajouter l'en-tête qu'il faut dans la case de l'adresse email de l'expéditeur

spammeur@anonyme.tld%0ASubject:Mon%20sujet%perso

Solutions

Plusieurs méthodes peuvent être envisagées pour éviter ce type d'injection, vous pouvez par exemple filtrer l'adresse que le script reçoit du formulaire afin de détecter les "%0A", "Bcc", "Subject", et autres éléments incongrus.

Vous pouvez également utiliser un test comme celui-ci:

<?php
if(!ereg('^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+'.
'@'.
'[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.
'[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$',
$_POST['email'])) mail($destinataire,$_POST['sujet'],$_POST['message'],"From: $_POST['email']\n")
?>

Dans ce cas l'email ne sera envoyé que si l'adresse entrée dans le formulaire semble correcte.

Attention: il existe de nombreuses manières de contrer la plupart des tests que vous pouvez effectuer, le code ci-dessus n'est pas garantit sans failles. Dans l'absolu, veiller à laisser le champ d'action le plus court possible aux intrusions.