I was contacted today about masses of spam being sent from a domain. It is a relatively simple php website with a contact form which contains name, email, phone and message. I cannot see any other way the site can be used to send spam messages to multiple users unless the whole server has been hacked.
The email is validated and bad chars are stripped from the body of the message. I have tried multiple ways to try and modify the headers through the form but can't seem to get anything to work so I am beginning to think the forms are secure.
This is the form validation:
$to='owner@website.com';
$messageSubject='Enquiry from the website';
$confirmationSubject='Your email to website.com';
$confirmationBody="Thankyou for your recent email enquiry to website.com.
Your email has been sent and we will get back to you as soon as possible.
The message you sent was:
";
$email='';
$body='';
$displayForm=true;
if ($_POST){
$email=stripslashes($_POST['email']);
$body=stripslashes($_POST['body']);
$name=stripslashes($_POST['name']);
$phone=stripslashes($_POST['phone']);
// validate e-mail address
$valid=eregi('^([0-9a-z]+[-._+&])*[0-9a-z]+@([-0-9a-z]+[.])+[a-z]{2,6}$',$email);
$crack=eregi("(|
)(to:|from:|cc:|bcc:)",$body);
$spam=eregi("http",$body);
$businessBody = "Enquiry from: $name
Email: $email
Phone: $phone
Message:
$body";
if ($email && $body && $phone && $name && $valid && !$crack & !$spam){
if (mail($to,$messageSubject,$businessBody,'From: '.$email."
") && mail($email,$confirmationSubject,$confirmationBody.$body,'From: '.$to."
")){
$displayForm=false;
echo "<div><p>Your message to us was sent successfully, and a confirmation copy has also been sent to your e-mail address.</p><p>Your message was:<br>".htmlspecialchars($body)."</p></div>";
}
else echo '<div class="emailMessage"><p>Something went wrong when the server tried to send your message. This might be due to a server error, and is probably not your fault. We apologise for any inconvenience caused. You are welcome to telephone us on 01383 625110</p></div>'; // the messages could not be sent
}
else if ($crack) echo '<div class="emailMessage"><p>Your message contained e-mail headers within the message body. This seems to be a cracking attempt and the message has not been sent.</p></div>'; // cracking attempt
else if ($spam) echo '<div class="emailMessage"><p>Your message contained characters that our system has flagged as spam email and has not been sent.</p></div>'; // spam mail!
else echo '<div class="emailMessage"><p>Your message could not be sent. You must complete all fields - name, phone number, e-mail address and a message.</p></div>'; // form not complete
}
Can anyone see a way this form can be abused?
It turned out someone had placed another encrypted file on the server built for mass mailing, so it wasn't actually coming from this form. Thanks for the answers anyway, they may help others!
Use a proper mailing class like SwiftMailer and you'll have less trouble (and nicer looking code, too). Typically these sorts of forms are abused by adding line breaks to the "from" or other headers, allowing them to set their own malicious headers.
For example:
if (mail($to,$messageSubject,$businessBody,'From: '.$email."
") && mail($email,$confirmationSubject,$confirmationBody.$body,'From: '.$to."
")){
While you've stripped slashes, you haven't stripped new lines. If I set my e-mail to be:
ceejayoz@example.com
Bcc: victim@example.com
victim@example.com gets BCCed on the e-mail. With some more clever stuff - turning it into a multipart e-mail and adding an extra default part - they can fully customize the e-mail.
it's possible to mass send if $_POST['email'] is:
usera@test.com,userb@test.com,userc@test.com
@ceejayoz's answer is good, although I see that you are attempting to prevent bcc's and newlines in your code, but only in the body of the email, not the email field. It's the email field that is most vulnerable to hacking.
Here's a bit of code I've used for years to protect the email field:
$value = "some@email.com";
if (!preg_match("/^[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i", $value)){
$error[$i] = "Invalid email address.";
}
//Nuke email header injection.
$submitted = $value;
$value = str_replace('\', '
', $value);
$value = str_replace('\
', '
', $value);
$value = str_replace('', '
', $value);
$value = str_replace(',', '
', $value);
$value = str_replace(';', '
', $value);
$value = str_replace(' ', '
', $value);
$value = explode('
', $value);
$value = $value[0];
if (trim($value) !== trim($submitted)) {
echo "Stop hacking me!";
}
}
Or use someone else's class, as ceejayoz says.
Also, consider captcha's and the rest, or limiting submissions per minute, as another way to add multiple levels of defence to your code.