Several months ago, my friend informed me that he was seeing a large volume of email spam coming from one of my legacy sites. After investigating, we found that my “contact” page was the source. A hacker was spamming people through the contact form on my website! The page in question was a simple PHP script where people could provide an email address and a short message that would be emailed to me. So here’s the question of the day: How did they make it email other people with their own custom email messages?
Most people may not be aware of this, but the culprit is the PHP mail() function. The relevant portion of the definition is as follows:
bool mail ( string $to, string $subject, string $message [, string $additional_headers] )
So most people would probably do something like this:
mail($to, $subject, $message);
But by default, this will create an email address with some ugly “from” address like, root@localhost. What if you want to have a “from” email address, such as the person who filled out the form?
mail($myEmailAddress, $subject, $message, “From: $fromAddress”);
But don’t you need to escape it? Well, a lot of beginners (like I did when I started out), don’t realize that “addslashes” does nothing. A hacker could provide additional headers in your script by typing in the following in your web-form:
Followed directly by another header:
Bcc : firstname.lastname@example.org [ignore spaces]
The above code would send an email to email@example.com through the BCC field. That alone doesn’t sound too threatening. However, it is actually possible to inject in a message body, attachments, other recipients, a new subject, etc. at this point. A hacker can completely re-format your original email. In essence, they can post data to your form to make it do something completely different than what you had intended.
And judging from the fact that I wasn’t getting emails, I would assume that they can suppress the original “to” email address as well, making the breach completely unnoticeable.
To fix this, make sure you filter arguments that get passed in as headers by removing the \r and \n characters.
$fromAddress = str_replace(array(“\r”, “\n”), ”, $formAddress);
As always, remember my code examples tend to use curly quotes that PHP won’t recognize.
So, is your form hacker-proof?
Further reading on this topic can be found here.
Note: I had a horrible time trying to make this post. Apparently, WordPress doesn’t like the word “Bcc[colon]” appearing anywhere in the post! How lame!?